Friday, January 26, 2007

vector can not hold reference to a pure virtual base class

I had three classes, a template pure virtual base class, a template
derived class and a third which I would like to use to store copies of
the derived class. The code looked like this:

#include <iostream>
#include <vector>

using namespace std;

template <class _prec> class Base {
public:
_prec i;

Base() {
i = 12;
}

virtual void f() = 0;

};

template <class _prec> class Derived : public Base<_prec> {
public:
void f() {
std::cout << this->i << std::endl;
}
};

template <class _prec> class Collect {
public:
vector <Base<_prec> *> vec;

Collect() {
}

void g(Base<_prec> &in) {
vec.push_back(&in);
vec[0]->f();
}
};

int main() {
Derived<int> *d = new Derived<int>;
Collect<int> c;

c.g(*d);

return 0;
}



And resulted in errors such as:

/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/vector.tcc:256: error: cannot allocate an object of abstract type ‘Base<int>’
base_vector_test.cpp:6: note: since type ‘Base<int>’ has pure virtual functions
/usr/lib/gcc/x86_64-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/vector.tcc:256: error: cannot declare variable ‘__x_copy’ to be of abstract type ‘Base<int>’
base_vector_test.cpp:6: note: since type ‘Base<int>’ has pure virtual functions



The problem is that vector creates a copy of the object you pass it. If you pass it a reference to an abstract base class it can't create a copy, just as you can't do: Base b; The solution in my case is to use pointers. This however means you'll have to manage their allocation and deallocation of the objects yourself. The fixed code looks like this:

#include <iostream>
#include <vector>

using namespace std;

template <class _prec> class Base {
public:
_prec i;

Base() {
i = 12;
}

virtual void f() = 0;

};

template <class _prec> class Derived : public Base<_prec> {
public:
void f() {
std::cout << this->i << std::endl;
}
};

template <class _prec> class Collect {
public:
vector <Base<_prec> *> vec;

Collect() {
}

void g(Base<_prec> &in) {
vec.push_back(&in);
vec[0]->f();
}
};

int main() {
Derived<int> *d = new Derived<int>;
Collect<int> c;

c.g(*d);

delete d;
return 0;
}



My original thread on comp.lang.c++ where I got help with this problem can be found here: http://groups.google.ie/group/comp.lang.c++/browse_thread/thread/c4cad258a9a94540

No comments: