继承的构造函数,默认构造函数和可见性

sky*_*ack 8 c++ default-constructor language-lawyer c++11 inherited-constructors

[namespace.udecl]/18所述:

[...]命名构造函数的using声明不会创建同义词; 相反,如果在用于构造相应基类的对象时可以访问附加构造函数,则可以访问这些附加构造函数,并忽略using-declaration的可访问性.[...]

因此,以下代码无法编译:

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }
Run Code Online (Sandbox Code Playgroud)

它返回的错误与所有主要编译器大致相同:

在这里宣布受保护

另一方面,以下代码编译:

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }
Run Code Online (Sandbox Code Playgroud)

它是否应该因为导致上一个示例中的错误的相同原因而无法编译?
它允许编译什么?

Som*_*ken 6

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }
Run Code Online (Sandbox Code Playgroud)

D在这种情况下没有用户定义的构造函数,因此编译器会为您调用B::B(但不是因为,using在这种情况下没有效果)生成一个(公共)构造函数,然后由main调用编译器生成的构造函数.

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }
Run Code Online (Sandbox Code Playgroud)

即使D这里没有用户定义的构造函数,也会隐式删除编译器生成B的构造函数,因为只有一个构造函数需要一个int.D还有一个构造函数,它接受int(using做了)但这个构造函数被标记protected,因此无法访问main.


son*_*yao 3

对于第二种情况,继承构造函数不生效。根据删除的隐式声明的默认构造函数的规则,在第二种情况下类D不会违反(有一个格式良好的B::B()for D);编译器将声明一个默认构造函数作为 的内联公共成员D,这使得D d{};工作正常。

...

T具有一个直接或虚拟基类,该基类具有已删除的默认构造函数,或者该基类不明确或无法从此构造函数访问。

...

对于第一种情况,继承构造函数生效:

(强调我的)

如果重载决议选择继承的构造函数,则如果它在用于构造相应基类的对象时可访问,则它是可访问的:引入它的 using 声明的可访问性将被忽略

如果重载决策在初始化此类派生类的对象时选择继承的构造函数之一,则继承该构造函数的 Base 子对象将使用继承的构造函数进行初始化,并且 Derived 的所有其他基类和成员都将按照默认值进行初始化默认构造函数(如果提供,则使用默认成员初始值设定项,否则发生默认初始化)。

然后由于访问隔离而失败。