Your virtual function A::foo() returns A* , and the function B<C>::foo() , which is intended to be overridden, returns C* .
This theoretically respects the principle of covariance, since C really is a specialization (comes from) A , but at the time of instantiation this is not known because C is an incomplete type.
One possible way to reconsider your design is to make A a class template, and also B pass the template argument for T to A :
template<typename T> class A { virtual T* foo() = 0; }; template<class T> class B : public A<T> { virtual T* foo() { return nullptr; } };
Regarding your workaround:
What does the standard say about this situation? Should this code compile? If not, why?
It should not be compiled, because the very fact of creating C also derived from A explicitly (note that in the end you get two different base sub-objects of type A inside C ) it does not make C full type when creating an instance of B<C> . In paragraph 9.2 / 2 of the C ++ 11 standard:
A class is considered a fully defined type of object (3.9) (or a full type) when closing } the class specifier. Within a class-class, a class is considered complete in functional bodies, default arguments, and copied or equal initializers for non-static data members (including such things in nested classes). Otherwise, it is considered incomplete in its class specification.
Andy prowl
source share