vector of pure virtual base class

Discussion in 'C++' started by nw, Jan 25, 2007.

  1. nw

    nw Guest

    Hi,

    I have 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 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);
    }
    };

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

    c.g(d);

    return 0;
    }

    This results in linking errors, which result from vector being unable
    to create a copy of the pure virtual class. Can anyone suggest how I
    should solve this?

    My first attempted was to make the function in Base virtual, rather
    than pure virtual (i.e. virtual void f() {}). This then compiles,
    however when the object is extracted from the vector (i.e. I do
    vec[0].f() in Collect), the base method is called not that of the
    derived class. Any ideas?

    I think this should all be standard C++ but I'm using gcc version 4.1.2
    to compile this code.

    Any help appreciated!
     
    nw, Jan 25, 2007
    #1
    1. Advertising

  2. nw

    mlimber Guest

    On Jan 25, 2:39 pm, "nw" <> wrote:
    > I have 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 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);
    > }
    >
    > };int main() {
    > Derived<int> d;
    > Collect<int> c;
    >
    > c.g(d);
    >
    > return 0;
    >
    > }This results in linking errors, which result from vector being unable
    > to create a copy of the pure virtual class. Can anyone suggest how I
    > should solve this?
    >
    > My first attempted was to make the function in Base virtual, rather
    > than pure virtual (i.e. virtual void f() {}). This then compiles,
    > however when the object is extracted from the vector (i.e. I do
    > vec[0].f() in Collect), the base method is called not that of the
    > derived class. Any ideas?
    >
    > I think this should all be standard C++ but I'm using gcc version 4.1.2
    > to compile this code.
    >
    > Any help appreciated!


    To operate on an object polymorphically, you need to either use a
    pointer or a reference to access it. std::vectors on the other hand,
    hold a copy of whatever object you put in them, so your vector either
    needs to be of Base*, or probably better, std::tr1::shared_ptr<Base>
    (aka boost::shared_ptr<Base>).

    BTW, I'd guess you're getting compiler errors, not linker errors.

    Cheers! --M
     
    mlimber, Jan 25, 2007
    #2
    1. Advertising

  3. nw

    Alan Johnson Guest

    On Jan 25, 11:39 am, "nw" <> wrote:
    > Hi,
    >
    > I have 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 looks like this:


    > This results in linking errors, which result from vector being unable
    > to create a copy of the pure virtual class. Can anyone suggest how I
    > should solve this?


    Templates are just obfuscating the core problem, which is that you are
    trying to instantiate an abstract class, which just can't be done.
    When you try to add to a vector of your abstract base type, you are
    essentially doing the following:

    class abstract_base
    {
    public:
    virtual int f() = 0 ;
    } ;

    class concrete : public abstract_base
    {
    virtual int f() { return 42 ; }
    } ;

    int main()
    {
    concrete c ;
    abstract_base ab(c) ; // Error, can't create an instance
    // of an abstract class.
    }


    Even if your base class was not abstract, virtual methods only get
    dynamically dispatched when called via pointers or references, so
    storing a vector of your base class still wouldn't achieve what you
    want.

    The solution? Store a vector of pointers to your base class. Example:
    std::vector<abstract_base *> v ;
    concrete c ;
    v.push_back(&c) ;

    If you want the vector to "own" the objects to which it points, then
    your easiest route will probably be to create the objects dynamically,
    and keep a vector of boost::shared_ptr.

    --
    Alan Johnson
     
    Alan Johnson, Jan 25, 2007
    #3
  4. nw

    nw Guest

    > The solution? Store a vector of pointers to your base class. Example:
    > std::vector<abstract_base *> v ;
    > concrete c ;
    > v.push_back(&c) ;
    >
    > If you want the vector to "own" the objects to which it points, then
    > your easiest route will probably be to create the objects dynamically,
    > and keep a vector of boost::shared_ptr.


    Many thanks for your and mlimber's advice, I'll give it a go!

    Thanks again!
     
    nw, Jan 26, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mitch Mooney
    Replies:
    2
    Views:
    375
    Bob Hairgrove
    Jun 18, 2004
  2. Replies:
    10
    Views:
    727
    Richard Herring
    Oct 18, 2005
  3. Arne Schmitz
    Replies:
    4
    Views:
    429
    Daniel Albuschat
    Jan 17, 2007
  4. Replies:
    2
    Views:
    564
  5. Martin
    Replies:
    5
    Views:
    473
    Felix Palmen
    Aug 26, 2010
Loading...

Share This Page