3

我有一个类(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!
  }
};
4

6 回答 6

4

你不能。这就是朋友的目的。

另一种方法是更改​​程序的设计/架构。但是对于这方面的提示,我需要更多的上下文。

于 2009-02-02T18:35:27.363 回答
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;
};
于 2009-02-02T18:56:53.123 回答
1

我认为你在这里有一个更大的问题。您的设计似乎不合理。

1)我认为“朋友”结构一开始就有问题

2)如果“朋友”不是你想要的,你需要重新检查你的设计。

我认为您要么需要做一些事情来完成工作,使用“朋友”,要么开发一个更强大的架构。看看一些 设计模式,我相信你会发现一些有用的东西。

编辑:

看到您的示例代码后,您肯定需要重新构建。A 类可能不在你的控制之下,所以这有点棘手,但可能希望你想将 B 类重新做为一个“有”类而不是“是一个”类。

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
    }

};
于 2009-02-02T18:41:32.313 回答
1

好吧 - 如果你想要你所描述的,那么朋友是最好的解决方案。每个编码标准都建议不要使用朋友,但替代设计更复杂 - 那么也许值得例外。

要解决没有朋友的问题将需要不同的架构

一种解决方案可能是使用一种形式的pImpl 习惯用法,其中“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);
}

当然现在你有了虚拟基础和多重继承!嗯....现在,这比一个朋友声明好还是坏?

于 2009-02-02T18:49:53.780 回答
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;
}
于 2009-02-03T09:14:55.717 回答
0

如果我理解:

  • A 将被其他开发人员子类化。
  • B 将由其他开发人员继承并从 A 继承。
  • A 有一些您不希望外部开发人员通过 B 访问的方法。

我不认为这可以在不使用朋友的情况下完成。我没有办法让超类的成员只对直接继承者可用。

于 2009-02-02T18:34:39.427 回答