Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template or abstract base class?

If I want to make a class adaptable, and make it possible to select different algorithms from the outside -- what is the best implementation in C++?

I see mainly two possibilities:

  • Use an abstract base class and pass concrete object in
  • Use a template

Here is a little example, implemented in the various versions:

Version 1: Abstract base class

class Brake { public: virtual void stopCar() = 0;   };  class BrakeWithABS : public Brake { public: void stopCar() { ... } };  class Car {   Brake* _brake; public:   Car(Brake* brake) : _brake(brake) { brake->stopCar(); } }; 

Version 2a: Template

template<class Brake> class Car {   Brake brake; public:   Car(){ brake.stopCar(); } }; 

Version 2b: Template and private inheritance

template<class Brake> class Car : private Brake {   using Brake::stopCar; public:   Car(){ stopCar(); } }; 

Coming from Java, I am naturally inclined to always use version 1, but the templates versions seem to be preferred often, e.g. in STL code? If that's true, is it just because of memory efficiency etc (no inheritance, no virtual function calls)?

I realize there is not a big difference between version 2a and 2b, see C++ FAQ.

Can you comment on these possibilities?

like image 505
Frank Avatar asked Mar 02 '09 14:03

Frank


People also ask

Is template class the same as abstract class?

The main difference is that abstract classes (run-time polymorphism) are a run-time mechanism, while templates are a compile-time mechanism. This means that by using abstract classes you can possibly change the behaviour at run-time (e.g, by loading a configuration file at run-time, or by means of plugins).

Can a template class be abstract?

Templates are a way of making your classes more abstract by letting you define the behavior of the class without actually knowing what datatype will be handled by the operations of the class.

Should base class be abstract?

Yes, it is reasonable and beneficial to mark explicitly as abstract a base class that should not be instantiated -- even in the absence of abstract methods. It enforces the common guideline to make non-leaf classes abstract. It prevents other programmers from creating instances of the class.

Can abstract class be a base class?

An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier ( = 0 ) in the declaration of a virtual member function in the class declaration.


1 Answers

This depends on your goals. You can use version 1 if you

  • Intend to replace brakes of a car (at runtime)
  • Intend to pass Car around to non-template functions

I would generally prefer version 1 using the runtime polymorphism, because it is still flexible and allows you to have the Car still have the same type: Car<Opel> is another type than Car<Nissan>. If your goals are great performance while using the brakes frequently, i recommend you to use the templated approach. By the way, this is called policy based design. You provide a brake policy. Example because you said you programmed in Java, possibly you are not yet too experienced with C++. One way of doing it:

template<typename Accelerator, typename Brakes> class Car {     Accelerator accelerator;     Brakes brakes;  public:     void brake() {         brakes.brake();     } } 

If you have lots of policies you can group them together into their own struct, and pass that one, for example as a SpeedConfiguration collecting Accelerator, Brakes and some more. In my projects i try to keep a good deal of code template-free, allowing them to be compiled once into their own object files, without needing their code in headers, but still allowing polymorphism (via virtual functions). For example, you might want to keep common data and functions that non-template code will probably call on many occasions in a base-class:

class VehicleBase { protected:     std::string model;     std::string manufacturer;     // ...  public:     ~VehicleBase() { }     virtual bool checkHealth() = 0; };   template<typename Accelerator, typename Breaks> class Car : public VehicleBase {     Accelerator accelerator;     Breaks breaks;     // ...      virtual bool checkHealth() { ... } }; 

Incidentally, that is also the approach that C++ streams use: std::ios_base contains flags and stuff that do not depend on the char type or traits like openmode, format flags and stuff, while std::basic_ios then is a class template that inherits it. This also reduces code bloat by sharing the code that is common to all instantiations of a class template.

Private Inheritance?

Private inheritance should be avoided in general. It is only very rarely useful and containment is a better idea in most cases. Common case where the opposite is true when size is really crucial (policy based string class, for example): Empty Base Class Optimization can apply when deriving from an empty policy class (just containing functions).

Read Uses and abuses of Inheritance by Herb Sutter.

like image 199
Johannes Schaub - litb Avatar answered Oct 24 '22 16:10

Johannes Schaub - litb