2009-02-02 83 views
3

我有一個類(A類),旨在由其他人寫的其他類繼承。 我還有另一個類(B類),它也繼承自A.公共和私人訪問爲相同的成員函數

B必須訪問某些不應被其他繼承類訪問的​​A的成員函數。

所以,這些A的成員函數應該公開爲B,但是對於其他人是私有的。

如何在不使用'friend'指令的情況下解決它?

謝謝。

編輯:例子爲什麼我需要它。

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

請問你能寫出爲什麼你需要這種方式嗎? – 2009-02-02 18:49:00

+0

那麼,代碼示例說明了爲什麼你需要它的語法,而不是爲什麼你需要它在設計方面。對於這樣一個小事情,朋友做它應該做的事情。有多少派生類需要朋友訪問? > 1? – gimpf 2009-02-02 21:45:05

回答

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; 
}; 
0

如果我的理解:

  • A將被其他開發者繼承。
  • B就被其他開發者的子類和繼承A.
  • A有一些方法你不想通過B.給外部開發者訪問

我不認爲這可以在不進行使用朋友。我不知道如何讓超類的成員僅用於指導繼承者。

4

你不能。這就是朋友的用途。

另一種方法是更改​​程序的設計/體系結構。但對於這個提示,我需要更多的上下文。

1

我想你在這裏遇到了更大的問題。你的設計看起來不太好聽。

1)我覺得「朋友」結構是有問題開始與

2)如果「朋友」是不是你想要的,你需要重新審視你的設計。

我認爲你需要做一些只是完成工作,使用'朋友'或開發更強大的架構。看看somedesign 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 
    } 

}; 
1

好 - 如果你想你所描述什麼,然後朋友是最好的解決方案。每個編碼標準建議不要使用朋友,但其他設計更復雜 - 那麼也許值得做個例外。

爲了解決不朋友的問題需要一個不同的體系結構

一種解決方案可以是使用其中「B」從內實現對象導出pImpl idiom的一種形式,而其它客戶端從外類派生。

另一個可能是在'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'的其他「吸氣劑」來解決。但是,你能說出這樣這個功能,因爲它不能被意外地叫:

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); 
} 

當然現在你有虛擬基地和多重繼承!嗯....現在,是比單朋友聲明更好或更差?

+0

如果您隨後將A重命名爲A_Internal,並將其重命名爲A,那麼您就是你想要的地方。 – xtofl 2009-02-02 18:52:49

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; 
}