Consider following code:
template<typename T>
struct MyTempl
{
virtual void doStuff(const T &value) = 0;
};
struct MyImpl : MyTempl<int>
{
void doStuff(const int &value) {}
};
struct MyPtrImpl : MyTempl<int*>
{
void doStuff(const int* &value) {}
};
MyImpl imp1;
MyPtrImpl imp2;
This will not compile correctly: the compiler tells me that doStuff()
in MyPtrImpl
is pure virtual, ie. I failed to correctly override it. If I however typedef int*
to something like int_ptr
, and use that as the template argument for MyPtrImpl
, everything works out.
Why is the compiler unable to deduct my intent without the typedef?
A class template can indeed contain virtual or pure virtual functions. This was employed by Andrei Alexandresu in "Modern C++ Design" to implement the visitor pattern using templates and type lists.
You cannot define a virtual template method. override only works for virtual methods, and you can only override methods with the same signature.
Because virtual functions are called only for objects of class types, you cannot declare global or static functions as virtual . The virtual keyword can be used when declaring overriding functions in a derived class, but it is unnecessary; overrides of virtual functions are always virtual.
A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.
You didn't specify the correct parameter type of the virtual function and thus you're not overriding it. This results in an abstract class since the virtual function is pure.
When specifying a parameter of a const reference type like
void doStuff(const int & value) {}
it's actually an alternative to write
void doStuff(int const & value) {}
which should be considered the "normal" way to declare a constant reference. When read from right to left this means "a reference to constant int
". Applying the same pattern to the pointer type int*
results in
void doStuff(int* const & value) {}
which compiles fine. But that one can't be written in the order like above, since that would mean something different: read const int* &
from right to left and you get "a reference to a pointer to a constant int
".
As you mentioned it, an alternative which works with the order from above can be written if you use typedef to alias the pointer type int*
:
typedef int *T;
void doStuff(const T & value) {}
which also compiles fine, since T
is now seen as a single literal type not introducing the ambiguities from above. In other words, the only option for how to read const T &
is "a reference to a const T
, which itself is a pointer to int
". It's a bit difficult to understand it intuitively, but what's not possible is to understand this as "a reference to a pointer to a constant int
", since this would not have a single T
in the description.
I recommend to use the keyword override
if you're using a C++11 compiler in order to detect problems like this (there are scenarios in which this problem will not result into a compilation error but into unexpected behavior; for example if the virtual function was not pure):
void doStuff(int* const & value) override {}
// ^^^^^^^^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With