我有一个类(A类),它被其他人编写的其他类继承。 我还有另一个类(B类),它也继承自A。
B必须访问其他继承类不应访问的某些A成员函数。
因此,这些A的成员函数应该是B公开的,但对其他人来说是私有的。
如何在不使用“朋友”指令的情况下解决问题?
谢谢。
编辑:我需要它的原因。
class A
{
public:
void PublicFunc()
{
PrivateFunc();
// and other code
}
private:
virtual void PrivateFunc();
};
class B : public class A
{
private:
virtual void PrivateFunc()
{
//do something and call A's PrivateFunc
A::PrivateFunc(); // Can't, it's private!
}
};
答案 0 :(得分:4)
你做不到。这就是朋友的目的。
另一种方法是更改程序的设计/体系结构。但是对于这方面的提示,我需要更多的背景。
答案 1 :(得分:3)
你说的是:A有两组子类。一组应该有访问权限,另一组不应该有。只有一个品牌的子类(即B)'看'A'的成员感觉不对。
如果您的意思是:只有我们可以使用此部分功能,而我们的客户则不能,还有其他度假胜地。
(通过继承进行功能重用通常会使您遇到这类问题。如果您通过聚合进行重用,您可能会解决它。)
建议:
// separate the 'invisible' from the 'visible'.
class A_private_part {
protected:
int inherited_content();
public:
int public_interface();
};
class B_internal : public A_private_part {
};
class A_export : private A_private_part {
public:
int public_interface() { A_private_part::public_interface(); }
};
// client code
class ClientClass : public A_export {
};
但更好的方法是采用聚合方式,将当前的“A”拆分为可见和不可见的部分:
class InvisibleFunctionality {
};
class VisibleFunctionality {
};
class B {
InvisibleFunctionality m_Invisible;
VisibleFunctionality m_Visible;
};
// client code uses VisibleFunctionality only
class ClientClass {
VisibleFunctionality m_Visible;
};
答案 2 :(得分:1)
我认为你这里有一个更大的问题。你的设计看起来不太合理。
1)我认为“朋友”结构从
开始是有问题的2)如果'朋友'不是你想要的,你需要重新检查你的设计。
我认为您需要做一些事情,只需完成工作,使用“朋友”或开发更强大的架构。看看some design patterns,我相信你会找到有用的东西。
编辑:
看到示例代码后,您肯定需要重新编写代码。 A级可能不在你的控制范围内,所以这有点棘手,但也许你想要重新将B级变为“有一个”类而不是“is-a”类。
public Class B
{
B()
{
}
void someFunc()
{
A a; //the private functions is now called and a will be deleted when it goes out of scope
}
};
答案 3 :(得分:1)
好吧 - 如果你想要你所描述的,那么朋友是最好的解决方案。每个编码标准建议不要使用朋友,但替代设计更复杂 - 那么也许值得做出例外。
要解决问题,没有朋友需要不同的架构
一种解决方案可能是使用pImpl idiom的形式,其中'B'派生自内部实现对象,而其他客户端派生自外部类。
另一种可能是在'A'和“其他客户”之间增加一层继承。类似的东西:
class A {
public:
void foo ();
void bar ();
};
class B : public A { // OK access to both 'foo' and 'bar'
};
class ARestricted : private A {
public:
inline void foo () { A::foo (); }; // Forwards 'foo' only
};
然而,这个解决方案仍然存在问题。 'ARestricted'无法转换为'A',因此需要通过“A”的其他“getter”来解决。但是,您可以将此函数命名为无法意外调用的方式:
inline A & get_base_type_A_for_interface_usage_only () { return *this; }
在尝试考虑其他解决方案后,假设您的层次结构需要按照您的描述进行,我建议您只使用朋友!
编辑:因此xtofl建议将类型'A'重命名为'AInternal',将'ARestricted'重命名为'A'。
这是有效的,除了我注意到'B'不再是'A'。然而,AInternal可以被虚拟遗传 - 然后'B'可以来自'AInternal'和'A'!
class AInternal {
public:
void foo ();
void bar ();
};
class A : private virtual AInternal {
public:
inline void foo () { A::foo (); }; // Forwards 'foo' only
};
// OK access to both 'foo' and 'bar' via AInternal
class B : public virtual AInternal, public A {
public:
void useMembers ()
{
AInternal::foo ();
AInternal::bar ();
}
};
void func (A const &);
int main ()
{
A a;
func (a);
B b;
func (b);
}
当然,现在你有虚拟基础和多重继承!嗯....现在,这比一个朋友宣言更好还是更差?
答案 4 :(得分:1)
我发现这是一个有趣的挑战。以下是我将如何解决问题:
class AProtectedInterface
{
public:
int m_pi1;
};
class B;
class A : private AProtectedInterface
{
public:
void GetAProtectedInterface(B& b_class);
int m_p1;
};
class B : public A
{
public:
B();
void SetAProtectedInterface(::AProtectedInterface& interface);
private:
::AProtectedInterface* m_AProtectedInterface;
};
class C : public A
{
public:
C();
};
C::C()
{
m_p1 = 0;
// m_pi1 = 0; // not accessible error
}
B::B()
{
GetAProtectedInterface(*this);
// use m_AProtectedInterface to get to restricted areas of A
m_p1 = 0;
m_AProtectedInterface->m_pi1 = 0;
}
void A::GetAProtectedInterface(B& b_class)
{
b_class.SetAProtectedInterface(*this);
}
void B::SetAProtectedInterface(::AProtectedInterface& interface)
{
m_AProtectedInterface = &interface;
}
如果您要一直使用这种模式,可以使用模板来减少代码。
template<class T, class I>
class ProtectedInterfaceAccess : public I
{
public:
void SetProtectedInterface(T& protected_interface)
{
m_ProtectedInterface = &protected_interface;
}
protected:
T& GetProtectedInterface()
{
return *m_ProtectedInterface;
}
private:
T* m_ProtectedInterface;
};
template<class T, class I>
class ProtectedInterface : private T
{
public:
void SetupProtectedInterface(I& access_class)
{
access_class.SetProtectedInterface(*this);
}
};
class Bt;
class At : public ProtectedInterface <::AProtectedInterface, Bt>
{
public:
int m_p1;
};
class Bt : public ProtectedInterfaceAccess<::AProtectedInterface, At>
{
public:
Bt();
};
class Ct : public At
{
public:
Ct();
};
Ct::Ct()
{
m_p1 = 0;
// m_pi1 = 0; // not accessible error
}
Bt::Bt()
{
SetupProtectedInterface(*this);
m_p1 = 0;
GetProtectedInterface().m_pi1 = 0;
}
答案 5 :(得分:0)
如果我理解:
我认为如果不使用朋友就可以做到这一点。我不知道如何让超类的成员只能直接使用继承者。