Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ templates and inheritance

My C++ framework has Buttons. A Button derives from Control. So a function accepting a Control can take a Button as its argument. So far so good.

I also have List<T>. However, List<Button> doesn't derive from List<Control>, which means a function accepting a list of Controls can't take a list of Buttons as its argument. This is unfortunate.

Maybe this is a stupid question, but I don't see how can I solve this :( List<Button> should derive from List<Control>, but I don't see a way to make this happen "automatically".

like image 407
ggambett Avatar asked Nov 24 '08 19:11

ggambett


People also ask

Can template class be inherited?

Inherited Member Functions of Class Templates are not Available.

Is inheritance better than templates?

Inheritance provides runtime abstraction. Templates are code generation tools. Because the concepts are orthogonal, they may happily be used together to work towards a common goal.

What is template inheritance?

Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your site and defines blocks that child templates can override. Sounds complicated but is very basic. It's easiest to understand it by starting with an example.

What is inheritance in C with example?

Inheritance in C++ Inheritance is a feature or a process in which, new classes are created from the existing classes. The new class created is called “derived class” or “child class” and the existing class is known as the “base class” or “parent class”. The derived class now is said to be inherited from the base class.


2 Answers

Stroustrup has an item on this in his FAQ:

Why can't I assign a vector<Apple*> to a vector<Fruit*>

You can solve it in two ways:

  • Make the List contain pointers to Control . Then accept List<Control*>
  • Make your function a template. You can still use List<Button> and List<Control> then, but it's more boilerplate code, and not necassary most of the time.

Here is code for the second alternative. The first alternative is already explained by other answers:

class MyWindow {
    template<typename T>
    void doSomething(List<T> & l) {
        // do something with the list...
        if(boost::is_same<Control, T>::value) {
            // special casing Control

        } else if(boost::is_same<Button, T>::value) {
            // special casing Button

        }

    }
};

To restrict doSomething only for List<derived from Control>, some more code is needed (look for enable_if if you want to know).

Note that this kind of code (looking what type you have) is rather to avoid. You should handle such things with virtual functions. Add a function doSomething to Control, and override it in Button.

like image 173
Johannes Schaub - litb Avatar answered Sep 28 '22 08:09

Johannes Schaub - litb


I hate to tell you but if you're using a list of instances to Control instead of pointers to Control, your buttons will be garbage anyway (Google "object slicing"). If they're lists of pointers, then either make the list<button*> into list<control*> as others have suggested, or do a copy to a new list<control*> from the list<button*> and pass that into the function instead. Or rewrite the function as a template.

So if you previously had a function called doSomething that took a list of controls as an argument, you'd rewrite it as:

template <class TControl>
void doSomething( const std::list<TControl*>& myControls ) {
  ... whatever the function is currently doing ...
}

void doSomethingElse() {
   std::list<Button*> buttons;
   std::list<Control*> controls;
   doSomething( buttons );
   doSomething( controls );
}
like image 44
Michel Avatar answered Sep 28 '22 09:09

Michel