此代码示例将描述我认为不直观的语言功能。
class A {
public:
A() {}
};
class B: private A
{
public:
B() {}
};
class C: public B
{
public:
C() {}
void ProcessA(A* a) {
}
};
int main() {
C c;
}
在 Mac 上使用 Apple LLVM 4.2 版编译此代码会产生一个
test.cc:16: error: ‘class A’ is inaccessible
test.cc:16: error: within this context
用 void ProcessA(::A* a)
替换 void ProcessA(A* a)
会使其构建,但我不明白为什么要使用绝对这里的类名。
它是一种语言功能,可以避免某些类型的错误,还是只是一个黑暗的 C++ 语法角落,比如在使用其他模板参数化的模板中的尖括号 (>>
) 之间放置空格的要求。
谢谢!
最佳答案
人类谈话
我将首先描述这里发生的事情——如果你已经知道这一点,请原谅我,但它为后续行动创造了必要的背景。
编译器解析不合格的A
至::C::A
(如果您自己在源代码级别进行更改,结果将是相同的)。从 ::C::A
无法访问会发出错误消息。
您建议编译器应该检测到 ::C::A
无法访问并且对 A
的引用然后应将其视为对 ::A
的引用作为后备。但是,::C::A
和 ::A
很可能是两个完全不同的东西。
在这里自动猜测应该做什么不仅容易引入错误和/或拉扯头发¹,而且完全违背了 C++ 的精神。
标准
直接根据 C++11 标准确认此行为符合设计要求。
§9/2 说:
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
这意味着在类 C
的范围内, A
是一个注入(inject)的类名。
§3.4/3 声明 injected-class-name 是名称查找的候选对象:
The injected-class-name of a class is also considered to be a member of that class for the purposes of name hiding and lookup.
§3.4/1 阐明了基础 A
的不可访问性不会阻止 injected-class-name A
从被考虑:
The access rules are considered only once name lookup and function overload resolution (if applicable) have succeeded.
§11.1/5 直接解释了所讨论的确切情况:
[Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. —end note ]
标准也给出了这个例子,和你的等价:
class A { };
class B : private A { };
class C : public B {
A *p; // error: injected-class-name A is inaccessible
::A *q; // OK
};
¹ 想象一下如果 A
会发生什么?最初是 public
基数,然后变为 private
在重构期间。还可以想象 ::A
和 ::C::A
是无关的。你会期望像 a->foo()
这样的电话(以前可以工作)会失败,因为 foo
不再可访问,而是 a
的类型在你背后发生了变化,你现在得到一个“没有方法foo
”的错误。啊?!?这当然远不是可能发生的最坏情况。
关于c++ - 将不可访问的私有(private)基类型的指针传递给派生类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15342410/