Inherited constructors, default constructor and visibility

老子叫甜甜 提交于 2019-12-23 07:49:10

问题


As stated by [namespace.udecl]/18:

[...] A using-declaration 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. [...]

Because of that, the following code does not compile:

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

It returns an error that is more or less the same with all the major compilers:

declared protected here

On the other side, the following code compiles:

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

Shouldn't it fail to compile instead for the same reasons that lead to an error in the previous example?
What does it allow it to compile?


回答1:


For the 2nd case, inheriting constructor doesn't take effect. According to the rules of deleted implicitly-declared default constructor, that in the 2nd case class D doesn't violate (there's a well-formed B::B() for D); the compiler will declare a default constructor as an inline public member for D, which makes D d{}; work well.

...

T has a direct or virtual base which has a deleted default constructor, or it is ambiguous or inaccessible from this constructor.

...

For the 1st case, inheriting constructors takes effect:

(emphasis mine)

If overload resolution selects an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.

If overload resolution selects one of the inherited constructors when initializing an object of such derived class, then the Base subobject from which the constructor was inherited is initialized using the inherited constructor, and all other bases and members of Derived are initialized as if by the defaulted default constructor (default member initializers are used if provided, otherwise default initialization takes place).

Then it fails because of the access isolation.




回答2:


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

D has no user-defined constructor in this case, so the compiler generates one (public) for you that calls B::B (but not because of the using, that has no effect in this case), that compiler-generated constructor is then called by main.

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

Even though D has no user-defined constructor here, the compiler-generated one is implicitly deleted because B only has a constructor that takes an int. D does also have a constructor that takes an int (using did that) but this constructor is marked protected and thus inaccessible by main.



来源:https://stackoverflow.com/questions/40081920/inherited-constructors-default-constructor-and-visibility

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!