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

时间:2016-10-17 08:42:34

标签: c++ c++11 language-lawyer default-constructor inherited-constructors

[namespace.udecl]/18所述:

  

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

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

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }

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

  

在此声明受保护

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

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }

由于导致上一个示例中出错的相同原因,不能编译失败吗?
它允许编译什么?

2 个答案:

答案 0 :(得分:6)

class B { protected: B() { } };
class D: B { using B::B; };
int main () { D d{}; }
在这种情况下,

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

class B { protected: B(int) { } };
class D: B { using B::B; };
int main () { D d{0}; }

即使D此处没有用户定义的构造函数,也会隐式删除编译器生成的构造函数,因为B只有一个构造函数需要intD也有一个构造函数,它使intusing执行了此操作),但此构造函数标记为protected,因此main无法访问。

答案 1 :(得分:3)

对于第二种情况,继承构造函数不会生效。根据{{​​3}}的规则,在第2个案例类D中没有违反(B::B()的格式D;编译器会将默认构造函数声明为D的内联公共成员,这使D d{};运行良好。

  

...

     

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

     

...

对于第一种情况,deleted implicitly-declared default constructor生效:

(强调我的)

  

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

     

如果重载决策选择了其中一个继承的构造函数   初始化此类派生类的对象,然后是Base子对象   从中使用。来初始化构造函数的继承   继承的构造函数,以及Derived的所有其他基础和成员   初始化,好像是默认的默认构造函数(默认成员   如果提供,则使用初始化程序,否则默认初始化   发生)。

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