C++基类外部访问私有嵌套类成员的可移植性问题
结论
这是完全符合C++标准的可移植特性,并非Apple Clang的编译器Bug,所有符合标准的编译器都会表现出相同行为。
核心规则
C++的访问控制规则作用于名字,而非类型本身或者类型的实例:
Base类将Nested嵌套类定义在private区域,意味着只有Base类的成员、友元可以直接使用Base::Nested这个名字,类外代码无权直接拼写这个私有名字。
不同写法的合规性解释
显式指定类型的报错写法
Base base{}; Base::Nested& nested = base.GetNested();
这段代码显式拼写了私有名字Base::Nested,触发访问控制检查,不符合标准要求,因此编译报错。
auto推导的合法写法
Base base{}; auto& nested = base.GetNested();
auto关键字让编译器自动推导nested的类型,全程不需要用户手动写出Base::Nested这个私有名字,因此不会触发访问控制的限制,符合标准要求,编译通过。
链式调用的合法写法
Base base{}; base.GetNested().DoSomething();
这段代码同样没有显式拼写Base::Nested名字,只是通过公有接口GetNested()拿到实例后直接调用其成员函数,访问控制规则不会阻止这种用法,因此编译通过。
补充说明
如果确实需要在类外显式声明该类型的变量,也可以用decltype规避私有名字访问问题,写法如下:
Base base{}; decltype(base.GetNested()) nested = base.GetNested();
这种写法也符合标准要求,可以正常编译。
内容的提问来源于stack exchange,提问作者Thambi
相关产品推荐
相关产品推荐

