views:

70

answers:

4

I would like to store pointers to a Base class in a vector, but then use them as function arguments where they act as a specific class, see here:

#include <iostream>
#include <vector>

class Base {};

template<class T>
class Derived : public Base {};

void Foo(Derived<int>* d) {
  std::cerr << "Processing int" << std::endl;
}

void Foo(Derived<double>* d) {
  std::cerr << "Processing double" << std::endl;
}

int main() {
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  Foo(vec[0]);
  Foo(vec[1]);
  delete vec[0];
  delete vec[1];
  return 0;
}

This doesn't compile:

error: call of overloaded 'Foo(Base*&)' is ambiguous

Is it possible to make it work? I need to process the elements of the vector differently, according to their int, double, etc. types.

+4  A: 

You'll need to use method polymorphism, as it's dynamic, rather than function overloading, which is static (compile-time). To overload on a templated type, you'll need to use template specialization.

Example:

#include <iostream>
#include <vector>

class Base {
  public:
    virtual void Foo() {
      std::cerr << "Processing base" << std::endl;
    }
};

template<class T>
class Derived : public Base {};

template <>
class Derived <int> : public Base {
  public:
    void Foo() {
      std::cerr << "Processing int" << std::endl;
    }
};

template <>
class Derived <double> : public Base {
  public:
    void Foo() {
      std::cerr << "Processing double" << std::endl;
    }
};

int main() {
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  vec[0]->Foo();
  vec[1]->Foo();
  delete vec[0];
  delete vec[1];
  return 0;
}
Max Shawabkeh
+1  A: 

When you typecast from Derived<int>* to Base*, you lose the information about what derived class you have, unless you use RTTI (RunTime Type Identification).

If you have enabled RTTI, then you can try to typecast a Base* forward to a derived type pointer by using dynamic_cast<>():

void Foo(Base* base)
{
    Derived<int>* derivedInt = dynamic_cast<Derived<int>*>(base);
    if(derivedInt)
    {
        Foo(derivedInt);
        return;
    }
    Derived<double>* derivedDouble = dynamic_cast<Derived<double>*>(base);
    if(derivedDouble)
    {
        Foo(derivedDouble);
        return;
    }
    // Handle other cases here.
}

dynamic_cast returns NULL if the pointer doesn't point to the correct type.

Alternatively, if you don't want to use RTTI and dynamic_cast, you have to maintain some means for determining which subclass is stored in your vector (usually an enum value stored along with the pointer, maybe in a pair, or with a method in Base that returns a similar enum) and use reinterpret_cast<>() to typecast the pointer.

Mike DeSimone
A: 

Of course it is ambiguous, how can the compiler figure out which specific subclass of Base is held in vec[0].

You can resolve the ambiguity by an explicit cast:

Foo( (Derived<int>*) vec[0] )

or, better, consider using dynamic method resolution:

class Base {
    virtual void Foo() = 0;
};

template <class T>
class Derived: Base {
    void Foo() { /* .. doFoo<T>(...) .. */ }
};

template<class T> void doFoo() { /* .. general case .. */ }
template<> void doFoo<int>() { /* .. int case .. */}
template<> void doFoo<double>() { /* .. double case .. */}

and in your code just call

vec[0]->Foo()
KT
+1  A: 

You can do it like this:

#include <iostream>
#include <vector>

class Base {
public:
        virtual void DoFoo() = 0;
};

template<class T>
class Derived : public Base {
public:
  virtual void DoFoo() {
          Foo(this);
  }
};

void Foo(Derived<int>* d) {
  std::cerr << "Processing int" << std::endl;
}

void Foo(Derived<double>* d) {
  std::cerr << "Processing double" << std::endl;
}


int main()
{
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  vec[0]->DoFoo();
  vec[1]->DoFoo();
  delete vec[0];
  delete vec[1];

  return 0;
}
Smilediver