Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ templates with interface objects

I have the following code that doesn't compile.

class Base {
    public:
        virtual ~Base() { };
};

class Derived : public Base { };

class NotDerived { };

template <typename T>
class Group { };

int main() {
    Group<Base> *g = NULL;

    g = new Group<Base>();       // Works
    g = new Group<Derived>();    // Error, but I want it to work

    g = new Group<NotDerived>(); // Error, as expected
}

I understand that this won't compile because g is a different type than Group<Derived>. To make this work in Java I would do something such as Group<? extends Base> g, but C++ doesn't have that keyword as far as I know. What can be done?

Edit: I would like to clarify that I do not want it possible to set types not derived from Base as g. I have updated my example to explain this.

Edit 2: There are two solutions to my problem. Dave's I found to be simple and easy to define. But Bowie's (along with Mark's additions) suited my needs better.

like image 307
Ryan Avatar asked Aug 25 '11 01:08

Ryan


2 Answers

The classes Group<Base> and Group<Derived> are entirely unrelated, different classes. Pointers to them are not convertible in either direction.

If you need runtime-polymorphic behaviour, your class template Group could derive from a common (non-templated) base class:

class Group // base
{
   virtual ~Group() { }
};

template <typename T>
class ConcreteGroup : public Group
{
  // ...
  T * m_impl;
};

Group * g1 = new ConcreteGroup<A>;
Group * g1 = new ConcreteGroup<B>;
like image 178
Kerrek SB Avatar answered Sep 19 '22 02:09

Kerrek SB


You could make Group< Base > a base class of all Group< T > T != Base.

class Base {
    public:
        virtual ~Base() { };
};

class Derived : public Base { };


template <typename T> class Group;

struct Empty { };

template <typename T>
struct base_for_group_t {
    typedef Group<Base> type;
};

template <>
struct base_for_group_t<Base> {
    typedef Empty type;
};

template <typename T>
class Group : public base_for_group_t<T>::type { };

int main() {
    Group<Base> *g = 0;

    g = new Group<Base>();    // Works
    g = new Group<Derived>(); //  now works
}
like image 28
Bowie Owens Avatar answered Sep 23 '22 02:09

Bowie Owens