2015-10-29 90 views
0

我已經實現了我的課程,可以說使用標準PIMPL成語的課程A。當我嘗試過載<<運營商爲我實現類AImplPIMPL成語可訪問性問題

/* A.h */ 
class A { 
public: 
    ... 
private: 
    class AImpl; 
    AImpl *impl; 
} 
/* Aimpl.h */ 
class AImpl { 
    ... 
    friend ostream &operator <<(ostream &os, const AImpl &impl); 
    ... 
} 
/* elsewhere.cpp */ 
ostream &operator <<(ostream &os, const AImpl &impl) { 
    ... 
} 

問題從重載運營商沒有獲得AImpl類莖
出現問題,宣佈A私人。
現在我處於如何解決這個問題的困境。一種方法是聲明類A的超負荷操作員朋友。另一種方式是公開類AImpl的私人申報。

哪種方法更好更安全?

+0

是的另一種方法是在'AImpl'裏面定義'operator <<',而不是隻聲明它。通常,對於pImpl,「Impl」類最好放置在「A.cpp」中,並且保持聲明和定義分離的效果很小,並且相當冗長。 –

+0

這是用於序列化還是打印?通常,你不想打印你班級的私人部分,所以你只需要一個操作符<< for A,它甚至不必是朋友。 – MikeMB

+0

無論如何,您爲什麼要訪問{{AImpl}} {{A.cpp}}以外的任何地方? –

回答

1

恕我直言,你濫用PIMPL成語。這個成語要求實現是非常私人的,即不應該在頭文件中定義AImpl(大家可以看到),而應該在A.cpp中定義,其中<<運算符也屬於此。

如果你這樣做,<<運算符也沒有意義在頭文件中聲明,那麼訪問PIMPL的唯一方法就是通過包含類。您可以定義ostream &operator <<(ostream &os, const A &obj),並將其作爲friendA

請注意,使用此方法,AImpl不需要限制訪問。無論如何,它的字段和大小隻能從A.cpp獲得。但是如果你想讓AImpl的內部爲private,你也可以使ostream &operator <<(ostream &os, const A &obj)friedAImpl

/* A.h */ 
class A { 
public: 
    ... 
private: 
    class AImpl; 
    AImpl *impl; 

    friend ostream &operator <<(ostream &os, const A &obj); 
} 

/* A.cpp */ 
class AImpl { 
public: 
    // OR: 
    friend ostream &operator <<(ostream &os, const A &obj); 

    ... 
} 

ostream &operator <<(ostream &os, const A &obj) { 
    AImpl* impl = obj.impl; 
    ... 
} 
+0

我很抱歉,因爲沒有足夠清晰地闡述我的問題。我想爲'A'和'AImpl'重載'<<'運算符,所以我可以使用'AImpl'的運算符來定義'A'的運算符。此外,我忽略提及* AImpl.h *是一個私人頭,而不是公共頭,所以我不認爲我濫用PIMPL。 但是,最好的解決方案似乎是超載只有運營商的主類,我發現約10分鐘後發佈這個問題。這似乎也是你的解決方案。 – Kijan

+0

@Kijan你仍然可以這樣做,但是因爲'AImpl.h'是私有的(只有'A.cpp'可以使用),所以頭文件的內容應該屬於'A.cpp')。 「AImpl」的運算符可能不需要訪問「A」:通常,pipml沒有任何對包含對象的引用,因此沒有「AImpl :: operator <<」所希望的「A」對象操作。 – skyking