假设我有以下类层次结构:
class Base
{
protected:
virtual void foo() = 0;
friend class Other;
};
class Derived : public Base
{
protected:
void foo() { /* Some implementation */ };
};
class Other
{
public:
void bar()
{
Derived* a = new Derived();
a->foo(); // Compiler error: foo() is protected within this context
};
};
我想我也可以更改a->Base::foo()
,但由于foo()
类中Base
是纯虚拟的,因此调用将导致调用Derived::foo()
。
然而,编译器似乎拒绝a->foo()
。我想这是合乎逻辑的,但我不能理解为什么。我错过了什么吗?不能(不应该)处理这种特殊情况吗?
谢谢。
答案 0 :(得分:6)
使用类名限定方法名称时,如Base::foo()
动态分派(运行时绑定)不适用。无论Base
是否为虚拟,它都始终调用foo()
的{{1}}实现。因为在这种情况下它是纯虚拟的,所以没有实现,编译器会抱怨。
你的第二个问题是在C ++中,友谊不是继承的。如果您希望foo()
具有对Other
的特殊访问权限,则需要成为Derived
的朋友。
另一方面,这有效:
Derived
因为在这里,您在Base* a = new Derived();
a->foo();
上呼叫foo()
,其中Base*
是公开的,并且因为您没有使用类名来限定foo()
,所以它使用动态调度并最终调用foo()
的{{1}}版本。
答案 1 :(得分:1)
我想你可以做到这一点
void bar()
{
Base* a = new Derived();
a->foo();
};
答案 2 :(得分:0)
尝试把这个“朋友类别人”;在派生类中。
更新:现在想想,我同意Tyler你应该改变一个Base指针。
Base* a = new Derived();
答案 3 :(得分:0)
然而,编译器似乎拒绝这样做。
拒绝什么?听起来好像你说编译器拒绝允许Other通过Base指针调用foo()函数。当然不应该这样。
回答你的基本问题,友谊不是继承的......期间。在与名称解析相同的阶段检查权限范围,并且由于foo()在您使用的名称中受到保护,因此您无法调用它。
另一方面,多态性通过指针重定向解决,与名称解析或访问权限无关。
答案 4 :(得分:0)
这很不幸,但在我看来,C ++中的友好性本来就被打破了:
我已经放弃了“按原样”使用它,现在我主要使用Key
模式(缺少更好的名称)。
///
/// Key definition
///
class Friend;
class FriendKey: boost::noncopyable { friend class Friend; FriendKey() {} };
///
/// Base/Derived definition
///
class Base
{
public:
void mySpecialMethod(const FriendKey&) { this->mySpecialMethodImpl(); }
private:
virtual void mySpecialMethodImpl() = 0;
}; // class Base
class Derived: public Base
{
public:
private:
virtual void mySpecialMethodImpl() {}
}; // class Derived
///
/// Friend definition
///
class Friend
{
public:
void mySpecialCall()
{
Derived d;
d.mySpecialMethod(FriendKey());
}
}; // class Friend
概念很简单:每个类都声明一个键(甚至可以在前向头中),而那些希望授予它们特殊访问权限的键只能使这个键成为可能。
它并不完美,因为你当然可以滥用它(通过密钥的传递性)。但是在C ++中你可以滥用一切,所以它更像是一个受到墨菲保护的问题而不是马基雅维利。