Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting a constructor from a private template class in C++

Why does class D compile, but class C does not?

class A {     public:         A(int) {} };  template <class T> class B : private T // Note: private base class {     public:        using T::T; };  class C : public B<A> {     public:         C() : B<A>(123) {}  // Error: 'class A A::A' is inaccessible };                          //         within this context  using BA = B<A>;  class D : public BA {     public:         D() : BA(123) {}  // OK }; 

I tested with GCC, Clang and Visual C++, and they are all the same. Changing class B : private T to public T solves the problem. But why? (Note that the using T::T is public.)

like image 232
Barnett Avatar asked Aug 23 '16 12:08

Barnett


People also ask

Can a class constructor be inherited?

Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.

How do you inherit constructors?

To inherit only selected ones you need to write the individual constructors manually and call the base constructor as needed from them. Historically constructors could not be inherited in the C++03 standard. You needed to inherit them manually one by one by calling base implementation on your own.

Can template class inherit?

Inheriting from a template classIt is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

Does inheritance inherit constructors?

Constructors are not inherited. The superclass constructor can be called from the first line of a subclass constructor by using the keyword super and passing appropriate parameters to set the private instance variables of the superclass.


1 Answers

Class A contains the injected-class-name A within its scope (that is, A::A refers to class A unless it happens to refer to the constructor).

Class B inherits this, so the name A within the scope of B refers to the injected-class-name A in scope of A. However, since A is a private base class of B, all names in scope of A are private within B.

Class C again inherits this, but it cannot access this A, since it is private within B. Hence the error. Note that the error is actually with using the name A in the construct B<A>.

Class BA doesn't have this problem, since the definition B<A> is not in the scope of any class, so the name A refers to the global name A and not to any injected-class-name. And of course, the name BA is public.

You can easily solve this by qualifying the name A in C:

class C : public B<A> { public:   C() : B<::A>( 123 ) {} }; 

Note that constructor inheritance has no effect there. The problem is with access to the class name A (injected in A and inherited in B and C), not with access to the constructor.

like image 61
Angew is no longer proud of SO Avatar answered Sep 21 '22 13:09

Angew is no longer proud of SO