16.4 Parameterized Virtuality
C++ allows us to parameterize directly three kinds of entities through templates: types, constants ("nontypes"), and templates. However, indirectly, it also allows us to parameterize other attributes such as the virtuality of a member function. A simple example shows this rather surprising technique:
// inherit/virtual.cpp #include <iostream> class NotVirtual { }; class Virtual { public: virtual void foo() { } }; template <typename VBase> class Base : private VBase { public: // the virtuality of foo() depends on its declaration // (if any) in the base class VBase void foo() { std::cout << "Base::foo()" << '\n'; } }; template <typename V> class Derived : public Base<V> { public: void foo() { std::cout << "Derived::foo()" << '\n'; } }; int main() { Base<NotVirtual>* p1 = new Derived<NotVirtual>; p1->foo(); // calls Base::foo() Base<Virtual>* p2 = new Derived<Virtual>; p2->foo(); // calls Derived::foo() }
This technique can provide a tool to design a class template that is usable both to instantiate concrete classes and to extend using inheritance. However, it is rarely sufficient just to sprinkle virtuality on some member functions to obtain a class that makes a good base class for more specialized functionality. This sort of development method requires more fundamental design decisions. It is therefore usually more practical to design two different tools (class or class template hierarchies) rather than trying to integrate them all into one template hierarchy.