3

In the following code you can see that I'm inheriting the base class ctors into the derived class under the "private" access specifier. My initial thought would be that these would adapt to the access specifiers that I have given (here "private") and hence not be available to use, but I seem to be mistaken. What are the rules for inheriting base class constructors and operators regarding access specifiers in the derived class?

Demo

#include <cstdio>

class base
{
public:
    base(int i) {
        printf("Public base class ctor called!");
    }
private:
    base(bool b) {
        printf("Private base class ctor called!");
    }
};


class derived final : public base
{
private:
    using base::base;
};

int main()
{
    derived d(2);

    // issues "is private within this context"
    // derived e(true);
}

Outputs:

Public base class ctor called!

(expected derived ctor to be "private" in this context)

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
glades
  • 3,778
  • 1
  • 12
  • 34
  • From [doc](https://en.cppreference.com/w/cpp/language/using_declaration#Inheriting_constructors): *"all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class."* – Jarod42 Jan 20 '23 at 15:27
  • @Jarod42 That doesn't sound right as a private ctor is not accessible in the derived class as well. See dervied e in the updated question. – glades Jan 20 '23 at 15:45
  • @glades: The private constructor introduced in `derived` is not inherited. So that clause doesn't apply. – Nicol Bolas Jan 20 '23 at 17:38
  • *visible to overload resolution* doesn't mean it will be accessible, but it will participate in overload resolution. Imagine that you have `base(char v)` constructor and `derived(int v)` constructor. Without `using base::base;` expression `derived d('c');` will compile sucessfully, but with `using` it won't. – sklott Jan 20 '23 at 17:43

1 Answers1

4

From The C++ 17 Standard (10.3.3 The using declaration)

19 A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored.

So as in your example the first constructor (with the parameter of the type int) is accessible in the base class then the corresponding inherited constructor in the derived class is also accessible.

On the other hand, the second constructor (with the parameter of the type bool) is private. So for the second object definition of the derived class

derived e(true);

the compiler will issue an error.

In fact inherited constructors also inherit access controls.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • `derived e(true)` will result in a diagnostic in any context where that constructor is not accessible. The `derived(bool)` constructor is identified as a candidate to be called, regardless of its accessibility. Then its access is checked and - for a non-`friend` non-member of `derived` there will be a diagnosable error. – Peter Jan 21 '23 at 00:47