此代码在VS2008中生成C2248 : 'A::B::ExceptionB' : cannot access private class declared in 'class A::B'
。
#include <iostream>
class A
{
class ExceptionA{};
class B
{
class ExceptionB{};
public:
B();
};
public:
A(int);
};
A::B::B()
{
throw ExceptionB();
}
A::A(int i)
{
i % 2 ? throw ExceptionA() : throw A::B::ExceptionB(); // C2248 !!
}
int main()
{
try
{
A a(3);
}
catch( A::ExceptionA& )
{
std::cout << "A::ExceptionA" << std::endl;
}
catch( A::B::ExceptionB& )
{
std::cout << "A::B::ExceptionB" << std::endl;
}
}
当然,如果我在ExceptionB{}
中公开课B
,代码就会编译。
但是我不明白为什么编译器不会抱怨main()
中的2个catch子句,因为A::ExceptionA
是A
和A::B::ExceptionB
中的私有类是A::B
中的私人课程。
答案 0 :(得分:3)
问题措辞有点奇怪,所以我假设你问为什么
i % 2 ? throw ExceptionA() : throw A::B::ExceptionB();
无法编译,而
catch( A::ExceptionA& )
catch( A::B::ExceptionB& )
确实
如果你看看你方便的花花公子C ++标准的副本(第11章,第4段),它会说:
应该注意,它是对受控制的成员和基类的访问,而不是它们的可见性。 成员名称仍然可见,并且仍然会考虑对基类的隐式转换 成员和基类是不可访问的。
上面的区别在于,在第一种情况下,您试图调用A::ExceptionA
或A::B::ExceptionB
的成员 - 异常的构造函数。但在catch语句中,您并未访问其中任何一个成员;您只能访问类型名称。
那就是说,我仍然认为这是MSVC ++中的一个错误。该标准还在第15.6章第1段中说:
如果catch子句中的exception-declaration具有类类型,并且发生catch子句的函数无法访问该类的析构函数,则该程序格式不正确。
你的样本似乎违反了,但MSVC ++正在接受它而没有投诉。
答案 1 :(得分:1)
这两个例外都是私有的,g ++,clang和EDG都抱怨它。也就是说,在C ++中使用它们可能是一个错误,但是你的编译器在允许代码时似乎是错误的。但是,关于异常处理的部分实际上没有明确说明被捕获的异常需要具有特定的访问权限(毕竟,私有类可以在“A”的成员中访问)。我想这导致开发人员不检查此访问权限。