以下代码显示了一个私有继承自接口的接口,该接口访问私有函数而不授予调用对象友谊。我对此感到困惑,但无法真正看到编译器可以提出哪些更好的解决方案(代码编译和运行)。为什么这样做?
#include <iostream>
class IVisitor;
class IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const = 0;
};
class VisitableA;
class VisitableB;
class IVisitor
{
public:
virtual void Visit(const VisitableA& a) = 0;
virtual void Visit(const VisitableB& b) = 0;
};
class VisitableA : public IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const
{
visitor.Visit(*this);
}
};
class VisitableB : public IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const
{
visitor.Visit(*this);
}
};
class PrivateVisitor : private IVisitor
{
public:
PrivateVisitor(IVisitable& v)
{
v.Accept(*this);
}
private:
virtual void Visit(const VisitableA& a)
{
std::cout << "I saw A\n";
}
virtual void Visit(const VisitableB& b)
{
std::cout << "I saw B\n";
}
};
int main(int argc, char* argv[])
{
VisitableA a;
VisitableB b;
PrivateVisitor p_a(a);
PrivateVisitor p_b(b);
}
答案 0 :(得分:4)
只在编译时检查访问说明符,并在那里检查应用它们的对象的静态类型。
在PrivateVisitor
内部构造函数中,*this
对象已投放到IVisitor
。在这种情况下,继承的类型并不重要,因为我们在PrivateVisitor
类型中,因此我们拥有完全访问权限。
该对象在IVisitable
对象(VisitableA
或VisitableB
)内使用,并调用Visit
成员函数。虽然对象的动态类型为PrivateVisitor
,但静态类型为IVisitor
(引用的类型为IVisitor&
)。对IVisitor
类检查访问说明符,其中Visit
重载都是 public ,因此编译器接受该调用。
最终覆盖中函数私有的事实并不重要,因为访问是通过基类执行的,其中函数是 public 。
答案 1 :(得分:1)
这里重要的私人是这一个:
PrivateVisitor : private IVisitor
幸运的是,PrivateVisitor被转换为IVisitor的唯一地方是构造函数:
PrivateVisitor::PrivateVisitor(IVisitable& v)
{
v.Accept(*this);
}
构造函数可以访问该类的私有库。
答案 2 :(得分:0)
private属于类范围,而不是对象范围。