class IFeature
{
public:
virtual std::string string() = 0;
};
class Feature2D
{
public:
virtual std::string string() { .... }
};
class Feature3D
{
public:
virtual std::string string() { .... }
};
void print(std::vector<IFeature*> & v)
{
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
void main()
{
std::vector<Feature2D*> v2d;
// push...
print(v2d); // compile error
std::vector<Feature3D*> v3d;
// push...
print(v3d); // compile error
}
Any suggestions on how I can obtain this print function? (maybe using another data structure different by std::vector)
Thanks
Use a template.
template<typename T> void print(std::vector<T *> const & v) {
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
Or, use a virtual print member function:
class IFeature
{
public:
virtual std::string string() = 0;
virtual void print(std::ostream & Dest) const = 0;
};
void print(std::vector<IFeature *> const & v) {
for (size_t i=0; i<v.size(); i++) {
v[i]->print(cout);
cout << endl;
}
}
Optionally combine with an operator<<
inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v) {
v.print(Dest);
return Dest;
void print(std::vector<IFeature *> const & v) {
for (size_t i=0; i<v.size(); i++)
std::cout << *(v[i]) << std::endl;
}
Just make the vectors IFeature* -vectors. You can store pointers for inherited classes in them just fine.
std::vector<IFeature*> v2d;
v2d.push_back(new Feature2D());
print(v2d);
No need to use templates. Pointers to the superclass are the way to go when you need to access common virtual functions. This way you can also mix different subclasses inside the same vector:
std::vector<IFeature*> vMixed;
vMixed.push_back(new Feature2D());
vMixed.push_back(new Feature3D());
print(vMixed);
Of course, if you also need pointers for the inherited classes, things get a bit more tricky. One option is to store them elsewhere separately. You can also downcast, but that is not usually recommendable.
For the sake of completeness, I'll add that you can reinterpret_cast the vectors, since all vector share the same binary code.
print(reinterpret_cast<std::vector<IFeature*>&>(v2d));
C++ doesn't have covariance for template parameters, but you can simulate it partly if you know what it does under the hood. I found reinterpret_cast to be also useful to convert vector<T*>& to vector<const T*>& for contravariance.
Granted, this is very ugly.
You can make print itself into a template:
template<typename T>
void print(T const &v)
{
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
Better yet, use iterators, then it'll work on most other standard containers as well:
template<typename T>
void print(T const &v)
{
for (T::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << (*i)->string() << std::endl;
}
Even better (thanks Pedro), pass the iterators themselves:
template<typename Iter>
void print(Iter begin, Iter end) {
for (Iter i = begin; i != end; ++i)
std::cout << (*i)->string() << std::endl;
}
What you are looking for here is interface covariance, which (as far as I know) is not possible on C++ classes. You need to make print also a Templated function (replace IFeature* with T*).
Related
I am new to coding and currently learning C++ to get started, so please excuse my narrow knowledge and very possible mistakes in code and general C++ lingo.
I have written a class of complex numbers called ComplexNumber with member variables being double re and double im with the obvious meanings. This class has a constructor, an empty constructor, a copy constructor, a destructor etc.
Using this I am now meaning to write a class ComplexVector of vectors with entries from ComplexNumber. For now I have defined the member variables to be a vector std::vector<ComplexNumber> vec and a size int size. Additionally I would like to define a member function void print(), again with the obvious meaning. The code I have so far is:
#include <iostream>
#include <vector>
#include "complex.h"
class ComplexVector {
private:
std::vector<ComplexNumber> vec;
int size;
public:
ComplexVector(std::vector<ComplexNumber> vector, int n){ //constructor
size = n;
vec = vector;
};
ComplexVector(){ //empty constructor
size = 0;
vec = {};
};
void print() const;
~ComplexVector(); //destructor
ComplexVector(const ComplexVector& v); //copy constructor
ComplexVector addition(ComplexVector w); //
ComplexVector subtraction(ComplexVector w); // i am not worrying about these for now
ComplexVector scale(ComplexNumber z); //
};
with defnitions
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
};
ComplexVector::~ComplexVector(){
std::cout << "calling destructor" << std::endl;
};
ComplexVector::ComplexVector(const ComplexVector& v){
size = v.size;
vec = v.vec;
};
Here is where I am getting a compiling error: in the definition of the print my compiler tells me
error: no viable conversion from '__wrap_iter<std::__1::vector<ComplexNumber, std::__1::allocator<ComplexNumber>
>::const_pointer>' to '__wrap_iter<std::__1::vector<ComplexNumber, std::__1::allocator<ComplexNumber> >::pointer>'
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
which I am not quite sure how to deal with. I have read something about certain member functions having to be defined for ComplexNumber to be used in an std::vector. I also played around with defining iterators inside of ComplexVector but this did not solve the problem. From my (to be fair very narrow) perspective there should be an iterator for vec and also corresponding begin()and end() functions. I have checked if I am passing arguments of the right type a thousand times, but I must be overlooking something.
One more thing to note is that I am very much aware that this is probably an extremely inefficient way to define a class like this. I have looked at multiple examples which used pointers to an array as the main member variable. I am surely going to implement something of that type next, but for now I want to understand where the mistake in my current code is. So thanks in advance for any answers.
One side question: I don't think I have understood the concept of a destructor very well (to be fair I haven't spent much time reading about it yet), but if anyone has a quick intuition about them, which he/she wants to share, that would be highly appreciated.
Also if you have any comments on style and/or other improvements of my code, I would appreciate it if you could share them.
Thank you!
Edit: Here is the ComplexNumberclass
class ComplexNumber {
private:
double re;
double im;
public:
ComplexNumber(double x, double y){
re = x;
im = y;
};
ComplexNumber(){
re = im = 0;
};
ComplexNumber(const ComplexNumber& z);
void print() const;
};
and definitions
void ComplexNumber::print() const {
if(im > 0){
std::cout << re << "+" << im << "i" << std::endl;
} else if(im < 0){
std::cout << re << im << "i" << std::endl;
} else {
std::cout << re << std::endl;
};
};
ComplexNumber::ComplexNumber(const ComplexNumber& z){
re = z.re;
im = z.im;
};
And a main method:
int main() {
std::vector<ComplexNumber> v1 = {ComplexNumber(1,2), ComplexNumber(4,2)};
int n = 2;
ComplexVector w1(v1,n);
w1.print();
return 0;
}
Your problem is here:
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
};
Notice that the function is marked const. This means any members of the class are treated as const qualified inside the method (i.e. you are not allowed to modify them). Thus when you call vec.begin() you are calling the const version of begin() on vector. This returns const_iterator not an iterator.
std::vector<ComplexNumber>::iterator it = vec.begin()
^^^^^^^^ should be const_iterator
A better way to solve this is to use auto and let the compiler work out the correct type:
auto it = vec.begin()
So the function becomes:
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::const_iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
}
or with auto:
void ComplexVector::print() const {
for(auto it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
}
or you can improve this by using the new version of for()
void ComplexVector::print() const {
for(auto const& item: vec){
std::cout << item << " ";
};
std::cout << "\n";
}
Note: When your code works. You can ask for a review on style at https://codereview.stackexchange.com
Follow up based on comments:
Try:
class ComplexNumber
{
......
friend std::ostream& operator<<(std::ostream& str, ComplexNumber const& data) {
data.print(); // You want to change this
// so you can pass the stream to print.
return str;
}
}
Hello I wanted to know if it was possible to do a thing like this ? // THANKS ! :)
struct PET
{
const char* pet;
const int age;
};
bool Sort(const PET& first, const PET& second)
{
return first.pet < second.pet;
}
void Foo(const std::vector<PET> pets)
{
std::sort(pets.begin(), pets.end(), Sort); /* Does not work */
std::cout << pets[0].pet;
std::cout << pets[0].age;
}
I completely agree with # Ulrich Eckhardt.
You cannot sort the vector as because the elements of your vector are not assignable.
I think, you might have gone confused with usage of const.
There is no need to make the structure variables const. The parameter of the custom sort function are generally kept as const because they should not be modifiable. This is a pattern which ensures safe coding practice.
Also, if you are using C++, I would suggest to use std::string instead of char*, as std::string is a cleaner, safer way to go because it removes the burden of memory management from the programmer.
Have a look at the working implementation, without use of const:
#include <string.h>
#include<iostream>
#include<vector>
#include<algorithm>
struct PET
{
std::string name;
int age;
};
bool compare(const struct PET& a, const struct PET& b){
return (a.name.compare(b.name) <= 0) ? true : false;
}
int main(){
std::vector<struct PET> vec(3);
vec[0].name = "dog";
vec[0].age = 3;
vec[1].name = "cat";
vec[1].age = 1;
vec[2].name = "bird";
vec[2].age = 2;
sort(vec.begin(), vec.end(), compare);
for(int i=0;i<3;i++){
std::cout<<vec[i].name<<" "<<vec[i].age<<std::endl;
}
return 0;
}
As #Deepak Tatyaji Ahire and #Ulrich Eckhardt said, you can't do what you wrote in your code.
const int can't be a variable. It is a constant for definition :)
The vector you wrote in your code can't be built that way.
I did not understand what you wanted to do with the "sort" function, I wrote the following to code, maybe it could help:
#include<iostream>
#include<vector>
struct PET
{
const char* pet;
int age;
PET(const char* c, int a) : pet(c) , age(a) {}
};
void Foo(PET &p, std::vector<PET> &v)
{
v.push_back(p);
/*do something here if needed*/
}
int main()
{
std::vector<PET> vect;
PET cat("Cat", 5);
PET dog("Dog", 10);
PET bird("Bird", 2);
Foo(cat, vect);
Foo(dog, vect);
Foo(bird, vect);
/*this is not elegant, you could define a function that give a list of
({Animal, age},...) to vector and then pushes back all these elements to the vector*/
for(int i=0; i<3; i++) std::cout<< vect[i].pet << ' ' << vect[i].age << std::endl; //std::cout << vect; if you are using an operator << overload
/*to overload the << operator in order to able to print the vector of struct PET:
std::ostream & operator << (std::ostream &os, std::vector<PET> &p)
{
os << "<";
for (int i = 0; i < p.size(); i++) {
os << p[i].pet;
os << ", ";
os << p[i].age;
if (i != p.size() - 1)
os << " - ";
}
os << ">\n";
return os;
}
*/
return 1;
}
AFAIK, there's no way to directly compare structures without defining their comparator.
Though in C++20, it introduces three-way comparison and you might be allowed to declare the Default comparisons by a single line. Very convenient. Unfortunately, there haven been no compiler implementing this feature.
For now, you have to manually define the comparator
inline bool cmp(const PET &lhs, const PET &rhs)
{
return std::strcmp(lhs.pet, rhs.pet)<0;
}
and pass it to std::sort
I have the following data structure
class FamilyMem
{
public:
string name;
string relation;
};
template<class T>
class Paerson
{
public:
string name;
int age;
vector<T> family;
};
I have a vector defined as the following
vector< Paerson<FamilyMem> > p;
I'm using this library and I want to call a function that uses templates, I'm trying to create my own version of the function but it is not working
// I initialize the vector p by calling this function
initPerson(p);
for(int i=0; i< p.size(); p++)
display(p[i]);
This is the function
template<class U>
struct Displaying< std::vector<U> >
{
typedef std::vector<U> Vector;
static void display(const Vector& v)
{
cerr << "Vector Size " << v.size();
}
}
I want to do something like this
template<class U>
struct Displaying< Paerson<FamilyMem> >
{
static void display(const Paerson<FamilyMem> v)
{
for (int i = 0; i < v.family.size(); i++)
cerr << "name " << v.family.name << " relation " << v.family.relation << "\n";
}
}
For some reason it is still calling the vector version and print the size
When performing template specialization, the proper syntax for your case would be template<> rather than template<class U>.
http://en.cppreference.com/w/cpp/language/template_specialization
I have this structure of classes.
class Interface {
// ...
};
class Foo : public Interface {
// ...
};
template <class T>
class Container {
// ...
};
And I have this constructor of some other class Bar.
Bar(const Container<Interface> & bar){
// ...
}
When I call the constructor this way I get a "no matching function" error.
Container<Foo> container ();
Bar * temp = new Bar(container);
What is wrong? Are templates not polymorphic?
I think the exact terminology for what you need is "template covariance", meaning that if B inherits from A, then somehow T<B> inherits from T<A>. This is not the case in C++, nor it is with Java and C# generics*.
There is a good reason to avoid template covariance: this will simply remove all type safety in the template class. Let me explain with the following example:
//Assume the following class hierarchy
class Fruit {...};
class Apple : public Fruit {...};
class Orange : public Fruit {...};
//Now I will use these types to instantiate a class template, namely std::vector
int main()
{
std::vector<Apple> apple_vec;
apple_vec.push_back(Apple()); //no problem here
//If templates were covariant, the following would be legal
std::vector<Fruit> & fruit_vec = apple_vec;
//push_back would expect a Fruit, so I could pass it an Orange
fruit_vec.push_back(Orange());
//Oh no! I just added an orange in my apple basket!
}
Consequently, you should consider T<A> and T<B> as completely unrelated types, regardless of the relation between A and B.
So how could you solve the issue you're facing? In Java and C#, you could use respectively bounded wildcards and constraints:
//Java code
Bar(Container<? extends Interface) {...}
//C# code
Bar<T>(Container<T> container) where T : Interface {...}
The next C++ Standard (known as C++1x (formerly C++0x)) initially contained an even more powerful mechanism named Concepts, that would have let developers enforce syntaxic and/or semantic requirements on template parameters, but was unfortunately postponed to a later date. However, Boost has a Concept Check library that may interest you.
Nevertheless, concepts might be a little overkill for the problem you encounter, an using a simple static assert as proposed by #gf is probably the best solution.
* Update: Since .Net Framework 4, it is possible to mark generic parameters has being covariant or contravariant.
There are two problems here: default constructions have the form MyClass c;; with parentheses it looks like a function declaration to the compiler.
The other problem is that Container<Interface> is simply a different type then Container<Foo> - you could do the following instead to actually get polymorphism:
Bar::Bar(const Container<Interface*>&) {}
Container<Interface*> container;
container.push_back(new Foo);
Bar* temp = new Bar(container);
Or of course you could make Bar or its constructor a template as Kornel has shown.
If you actually want some type-safe compile-time polymorphism, you could use Boost.TypeTraits is_base_of or some equivalent:
template<class T>
Bar::Bar(const Container<T>& c) {
BOOST_STATIC_ASSERT((boost::is_base_of<Interface, T>::value));
// ... will give a compile time error if T doesn't
// inherit from Interface
}
No. Imagine that the container parameter is "hardcoded" into the class it defines (and that is actually how it works). Hence the container type is Container_Foo, that is not compatible with Container_Interface.
What you might try however is this:
template<class T>
Bar(const Container<T> & bar){
...
}
Yet you loose direct type checking that way.
Actually the STL way (probably more effective and generic) would be to do
template<class InputIterator>
Bar(InputIterator begin, InputIterator end){
...
}
... but I assume you don't have iterators implemented in the container.
It is possible to create an inheritance tree for containers, reflecting the inheritance tree of the data. If you have the following data:
class Interface {
public:
virtual ~Interface()
{}
virtual void print() = 0;
};
class Number : public Interface {
public:
Number(int value) : x( value )
{}
int get() const
{ return x; }
void print()
{ std::printf( "%d\n", get() ); };
private:
int x;
};
class String : public Interface {
public:
String(const std::string & value) : x( value )
{}
const std::string &get() const
{ return x; }
void print()
{ std::printf( "%s\n", get().c_str() ); }
private:
std::string x;
};
You could also have the following containers:
class GenericContainer {
public:
GenericContainer()
{}
~GenericContainer()
{ v.clear(); }
virtual void add(Interface &obj)
{ v.push_back( &obj ); }
Interface &get(unsigned int i)
{ return *v[ i ]; }
unsigned int size() const
{ return v.size(); }
private:
std::vector<Interface *> v;
};
class NumericContainer : public GenericContainer {
public:
virtual void add(Number &obj)
{ GenericContainer::add( obj ); }
Number &get(unsigned int i)
{ return (Number &) GenericContainer::get( i ); }
};
class TextContainer : public GenericContainer {
public:
virtual void add(String &obj)
{ GenericContainer::add( obj ); }
String &get(unsigned int i)
{ return (String &) GenericContainer::get( i ); }
};
This is not the best performing code; it is just to give an idea. The only problem with this approach is that every time you add a new Data class, you have to also create a new Container. Apart from that, you have polymorphism "working again". You can be specific or general:
void print(GenericContainer & x)
{
for(unsigned int i = 0; i < x.size(); ++i) {
x.get( i ).print();
}
}
void printNumbers(NumericContainer & x)
{
for(unsigned int i = 0; i < x.size(); ++i) {
printf( "Number: " );
x.get( i ).print();
}
}
int main()
{
TextContainer strContainer;
NumericContainer numContainer;
Number n( 345 );
String s( "Hello" );
numContainer.add( n );
strContainer.add( s );
print( strContainer );
print( numContainer );
printNumbers( numContainer );
}
I propose the following workaround, which employs a template function. Although the example use Qt's QList, nothing prevents the solution from being straightforwardly transposed to any other container.
template <class D, class B> // D (Derived) inherits from B (Base)
QList<B> toBaseList(QList<D> derivedList)
{
QList<B> baseList;
for (int i = 0; i < derivedList.size(); ++i) {
baseList.append(derivedList[i]);
}
return baseList;
}
Pros:
general
type-safe
fairly efficient if the items are pointers or some other cheaply copy-constructible elements (such as implicitly shared Qt classes)
Cons:
requires the creation of a new container, as opposed to enabling the reuse of the original one
implies some memory and processor overhead both to create and to populate the new container, which depend heavily on the cost of the copy-constructor
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
struct Base { int b = 111; };
struct Derived: public Base { };
struct ObjectStringizer {
template <typename T>
static std::string to_string(const T& t) {
return helper<T>()(t);
}
template <typename T, typename = void>
struct helper {
std::string operator()(const T& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
};
template <typename T>
struct helper<T, typename std::enable_if<std::is_base_of<Base, T>::value>::type> {
std::string operator()(const T& base) {
return to_string(base.b);
}
};
template <typename T>
struct helper<std::vector<T>> {
std::string operator()(const std::vector<T>& v) {
std::ostringstream oss;
for (size_t i = 0, sz = v.size(); i < sz; ++i) {
oss << (i ? "," : "") << to_string(v[i]);
}
return "[" + oss.str() + "]";
}
};
template <typename Key, typename Value>
struct helper<std::map<Key, Value>> {
std::string operator()(const std::map<Key, Value>& m) {
std::ostringstream oss;
for (auto iter = m.begin(), iter_end = m.end(); iter_end != iter; ++iter) {
oss << (m.begin() != iter ? "," : "") << to_string(iter->first) << ":" << to_string(iter->second);
}
return "{" + oss.str() + "}";
}
};
};
int main(int argc, char* argv[]) {
std::cout << ObjectStringizer::to_string("hello ") << ObjectStringizer::to_string(std::string("world")) << std::endl;
std::cout << ObjectStringizer::to_string(Derived()) << std::endl;
std::cout << ObjectStringizer::to_string(std::vector<int>{3, 5, 7, 9}) << std::endl;
std::cout << ObjectStringizer::to_string(std::map<int, std::string>{{1, "one"}, {2, "two"}}) << std::endl;
return 0;
}
container is a container of Foo objects not a container of Interface objects
And it cannot be polymorphic either, pointers to things can be ,but not the objects themselvs. How big would the slots in the container have to be for container if you could put anything derived from interface in it
you need
container<Interface*>
or better
container<shared_ptr<Interface> >
I have a finite amount of classes with the nearly-same implementation, the only different being the underlying type of data they manipulate:
class IntContainer
{
public:
void setData(int data);
int getData();
int _data;
};
class BoolContainer
{
public:
void setData(bool data);
bool getData();
bool _data;
};
class StringContainer
{
public:
void setData(std::string data);
std::string getData();
std::string _data;
};
// Etc. You get the idea.
I'd like to reduce the code duplication of these classes by using templates like so:
template<typename T>
class GenericContainer
{
public:
void setData(T data);
T getData();
T _data;
};
And specialization:
typedef GenericContainer<int> IntContainer;
typedef GenericContainer<bool> BoolContainer;
typedef GenericContainer<std::string> StringContainer;
This works well. But I'd also like to add an abstract base class to these specialized classes to be able to manipulate them in a generic way (eg. in a collection). The problem is this base class should have the getData and setData methods to be able to call them even without knowing the dynamic type of the object manipulated.
I would implement it with something like this:
class Base
{
public:
virtual void setData(??? data) = 0;
virtual ??? getData() = 0;
};
// Modify GenericContainer's definition like so
template<typename T>
class GenericContainer : Base { ... }
And use it somehow like that:
int main(int argc, char const *argv[])
{
IntContainer intc = IntContainer();
intc.setData(42);
std::cout << intc.getData() << std::endl;
BoolContainer boolc = BoolContainer();
boolc.setData(false);
std::cout << boolc.getData() << std::endl;
std::vector<Base> v;
v.push_back(intf);
v.push_back(boolf);
for (std::vector<Base>::iterator it = v.begin() ; it != v.end(); ++it)
std::cout << it->getData() << std::endl;
return 0;
}
The problem is I don't know how to write the Base methods prototypes as the type is unknow (and does not matter, the derived class implementation should be called at runtime based on the dynamic type of the object).
TL;DR: How to implement an abstract base class over several fully specialized templated classes ?
There is simply no way to do what you want.
The problem is, if this was allowed, the compiler would have to generate as many virtual methods in the base class as there are possible specializations of the template child class (ie. an infinity) which is not possible.
How about making base template too? Of course there is no way you can do something like
std::vector<Base> v;
v.push_back(intf);
v.push_back(boolf);
but the rest you can achieve with something simple as
template<typename T>
class Base
{
public:
virtual void setData(T data) = 0;
virtual T getData() = 0;
};
// Modify GenericContainer's definition like so
template<typename T>
class GenericContainer : Base<T> {
T d;
public:
virtual void setData(T data) {d = data;}
virtual T getData() { return d; }
};
You can use it in any way as long as types match.
IntContainer intc = IntContainer();
intc.setData(42);
std::cout << intc.getData() << std::endl;
BoolContainer boolc = BoolContainer();
boolc.setData(true);
std::cout << boolc.getData() << std::endl;
std::vector<IntContainer> v;
v.push_back(intc);
// v.push_back(boolc); No can't do.
This is a solution for any types of classes that can round-trip through a stringstream, and such conversion is the right way to convert between types. It isn't efficient at all:
struct BaseContainer {
protected:
boost::any data;
std::function< std::string( boost::any const& ) > toString;
virtual void setDataAny( boost::any x, std::function< std::string( boost::any const& ) > convert ) {
data = x;
toString = convert;
}
public:
virtual boost::any getDataAny() const {
return data;
}
template<typename T>
void setData( T const& t ) {
setDataAny( boost::any(t), []( boost::any const& a )->std::string {
std::string retval;
std::stringstream ss;
try
{
ss << boost::any_cast< T >(a);
ss >> retval;
return retval;
} catch(const boost::bad_any_cast &) {
return retval;
}
});
};
template<typename T>
struct TypedContainer:BaseContainer {
public:
T getData() const {
T retval;
try {
retval = boost::any_cast<T>(getDataAny());
return retval;
} catch(const boost::bad_any_cast &) {
std::string str = toString( getDataAny() );
std::stringstream ss;
ss << str;
ss >> retval;
return retval;
}
}
};
with fewer types, you could do something similar, so long as you have conversion functions between them.
Alternatively, if you like exceptions, you could throw.
Alternatively, you could use boost::variants, which do no conversions, but work from a finite list of types (they are basically tagged unions that support more types than C++03 lets union do, and with some nice semantics on assign/copy/etc).
Assuming you have some design flexibility, you can change your interface to accommodate this, although its not as efficient as an infinite virtual table
You can set values through construction, or >>
You can get values through <<
Your vector needs to be a base pointer or reference, the size of each base object is variable, the pointer, explicit or implicit through a reference is of fixed size
Notice that copies are more efficient if the compiler knows that it is copying from one generic to another as opposed to base to base
#include <iostream>
#include <sstream>
#include <vector>
class gen_base
{
public:
virtual std::ostream & output(std::ostream& S) const = 0;
virtual std::istream & input(std::istream& S) = 0;
friend std::istream & operator >> (std::istream &S, gen_base &g) {
return g.input(S);
}
friend std::ostream & operator << (std::ostream &S, const gen_base &g) {
return g.output(S);
}
};
template<typename T>
class GenericContainer : public gen_base
{
public:
GenericContainer(T data) : _data(data) {}
GenericContainer(const gen_base& other) {
// std::cout << "EXPENSIVE" << std::endl;
std::stringstream cvt;
other.output(cvt);
input(cvt);
}
template <class U>
GenericContainer(const GenericContainer<U>& other)
{
// std::cout << "CHEAP" << std::endl;
_data=other.getData();
}
virtual std::istream & input(std::istream &S) {
return (S >> _data);
}
virtual std::ostream & output(std::ostream &S) const {
return (S << _data);
}
T getData() const {
return _data;
}
private:
T _data;
};
typedef GenericContainer<int> IntContainer;
typedef GenericContainer<bool> BoolContainer;
typedef GenericContainer<std::string> StringContainer;
int main(int argc, char const *argv[])
{
IntContainer * intc = new IntContainer(42);
std::cout << *intc << std::endl;
gen_base * boolc = new BoolContainer(*intc);
std::cout << *boolc << std::endl;
IntContainer * intc2 = new IntContainer(*boolc);
std::cout << *intc2 << std::endl;
std::vector<gen_base *> v; // has to be pointer to base;
v.push_back(intc);
v.push_back(boolc);
v.push_back(intc2);
for (std::vector<gen_base *>::iterator it = v.begin() ; it != v.end(); ++it)
std::cout << **it << std::endl;
delete intc;
delete boolc;
return 0;
}