0

In Java, I use

ArrayList<Object> contents = new ArrayList<Object>();

to hold generic types, and elements are not meant to be of the same type.

For example, I did things like :

int n = 1991;
String str = "mfso";
contents.add(n);
contents.add(str);

Now, I would like to do the same thing in C++, but I found nothing alike. I tried `void**, but it is very C-like and too hard to harness. I want a more OO flavor solution.

I hope you can show me different solutions and briefly tell me the pros&cons.

Thanks in advance

KeCen Zhou

1
  • 1
    To be honest, storing any type in a container is not particularly OO. You end up having to make a lot of if() type branches that OO is supposed to avoid. To be OO you really need the types stored in the container to be strongly related so each type is a variety of some common base type interface. Commented Apr 7, 2015 at 22:28

3 Answers 3

1

C++ doesn't have such a "universal base-class" like Java's Object class. So, this mechanism has to be created some other way.

For a truly "anything" container, the only general solution is to use something like boost::any from the Boost.Any library (which might also be supported by some compilers as std::experimental::any, as described here). There is obviously overhead to using this, but I assume this is something you are prepared to live with.

Here is how you could use it:

#include <vector>
#include <string>
#include <iostream>
#include <typeinfo>

#include <boost/any.hpp>

int main() {
  std::vector< boost::any > contents;

  int n = 1991;
  std::string str = "mfso";
  contents.emplace_back(n);
  contents.emplace_back(str);

  for(auto& x : contents) {
    if( x.type() == typeid(int) )
      std::cout << " Int: " 
                << boost::any_cast< int >(x) << std::endl;
    else if( x.type() == typeid(std::string) )
      std::cout << " String: " 
                << boost::any_cast< std::string& >(x) << std::endl;
  };
};

Ideally, you should avoid using something like boost::any if you can solve your problem some other way. For example, if all types of objects are related (or can be related) through some base-class, then you should use that. Or, if you have a limited number of types that you expect to store in the container, then you can use something like boost::variant instead (see docs).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. I think a rather direct translation from Java to C++ is impossible, and I shouldn't have assumed so.
0

You are looking to use a template. A template is a C++ language construct that allows the compiler to generate multiple versions of a class type or a function by allowing parameterized type (mine).

template <class Obj>
class Foo
{
   private:
      Obj n;
      int x;
      //... more variables etc..

}

Implementation:

Foo<string> t;
Foo<yourObject> s;
t.yourmethod(someParam);

Comments

0

If you don't want the overhead of boost in your project (which is quite big, if you ask me) you can do the following:

std::vector<void*> contents;

int n = new int(9);
std::string s = new string("hello");
contents.push_back(n);
contents.push_back(s);

// get the contents
if (typeid(*contents[0]).name() == std::string("int")) {
    std::cout << "contents[0] is an int" << std::endl;
}
// so on and so forth

Note that this is not the C++ way of doing things. If you're going to try to write Java inside C++ you're going to have a hard time, so I suggest learning the idiomatic way of doing things.

1 Comment

That technique is not portable since the string returned by type_info::name is implementation defined.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.