2

How do I create a Derived class and have the Base class instantiated when creating a derived class.

Like this

template<class T> 
struct Base 
{
  typedef T type;
  static const int n = 3;
  virtual int f() = 0;
  int f(int x) { return x * 2; }
};

// doesn't compile!
template<class T> 
struct Derived : Base<T> 
{
    type field;         // The compiler doesn't know Base<T>::type yet!
    int f() { return n; } // the compiler doesn't know n yet, and f(int) is maksed!
};
Claudiordgz
  • 3,023
  • 1
  • 21
  • 48

3 Answers3

3

You can bring in the relevant names with a using declaration:

template<class T> 
struct Base 
{
  typedef T type;
  static const int n = 3;
  virtual int f() = 0;
  int f(int x) { return x * 2; }
};

template<class T> 
struct Derived : Base<T> 
{
    using typename Base<T>::type;
    using Base<T>::n;

    type field;
    int f() { return n; }
};

Live example

For types inherited in this way, you also have to use the typename keyword (as I did above), so that the compiler knows the name refers to a type. There's a question on SO with more info about this requirement.

An alternative is to explicitly qualify the names: use typename Base<T>::type instead of type and Base<T>::n instead of n. Which you choose is largely a matter of preference.

Community
  • 1
  • 1
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

Until you instantiate Derived for some type T, the compiler has no way to guess where type and n are supposed to come from. After all, it's legal to provide specializations of Base for different types after defining Derived.

All you need to change is:

template<class T> 
struct Derived : Base<T> 
{
    typename Base<T>::type field; // tell the compiler it's a type,
                                  // and where it comes from
    int f() { return Base<T>::n; }// tell the compiler where n comes from too
};

The using declaration works the same way, by qualifying those names, and it may end up looking cleaner if you use each name multiple times.

Useless
  • 64,155
  • 6
  • 88
  • 132
0

The are a number of ways you could do this, if you want your Derived class to use the Base class naturally you could try using a template of templates.

Suppose you have the same Base Class, then derived would have to look like this:

template< class T, template<typename> class Base > 
struct Derived : Base<T> 
{
    typename Base<T>::type field; 
    int f() 
    {
      return n;
    }
    int f(int x)
    {
      return Base<T>::f(x);
    }
};

But to instantiate the Derived class you would need to specify the Base class as well.

Like this

Derived<int, Base> object; 

Now let's say you don't want that, you just want to instantiate Derived objects from the SAME base class, then you must specialize the derived template.

template< class T, template<typename> class Base = Base > 
struct Derived : Base<T> 
{
    Base<T>::type field; 
    int f() 
    {
       return n;
    }
    int f(int x)
    {
        return Base<T>::f(x);
    }
};

This way you can now create Derived<int> or Derived<string>

LIKE THIS

int main()
{
    Derived<int> bs1;
    bs1.field = 200;
    std::cout << bs1.f() << std::endl;
    std::cout << bs1.f(50)<< std::endl;
    std::cout << bs1.field<< std::endl;

    Derived<std::string> bs2;
    bs2.field = "example";
    std::cout << bs2.f() << std::endl;
    std::cout << bs2.f(50)<< std::endl;
    std::cout << bs2.field<< std::endl;

    return 0;
}

When you should do this?

When you intend to be switching the base class for some reason, could be for Test Cases. Changing the base class could also change the context.

You could also create a template typedef which would allow you to bring the base property to your own Derived class. This is a good approach.

Claudiordgz
  • 3,023
  • 1
  • 21
  • 48
  • 1
    Can you explain *why* such complexity should be necessary? – Angew is no longer proud of SO Mar 12 '14 at 19:28
  • As with everything it depends on your application. The real question is why the implementation should depend on the interface when it could be tje other wau around. Another thing, if you call this complexity then clearly you need to keep digging into design patterns. – Claudiordgz Mar 12 '14 at 20:00
  • 1
    I don't call this complexity in the absolute sense - I use Boost.Preprocessor and template metaprogramming regularly :-) But I don't understand why you introduce a template parameter for something which doesn't need it. You claim "To inherit a Template Class successfully it is necessary to specify you are inheriting from a Template. ... derived would have to look like this:" These are simply incorrect statements. – Angew is no longer proud of SO Mar 12 '14 at 20:17
  • You are absolutely right about this, i shall edit my answer for a more correct explanation. – Claudiordgz Mar 12 '14 at 20:24