定義:
class B
{
private:
B()
{
}
friend class A;
};
將導致B無法被除A以外的其它任何class直接繼承以後實例化,也就是說,在上面這個定義的基礎上,如果你在定義:
class C:public B{};
將導致編譯能夠通過,但是無法實例化C(那當然也沒用了,所以間接實現了一個無法繼承的類B),但是因爲A是B的友元,所以能夠進入B的private區域,所以如果定義:
class A:public B{};
能夠實例化A.
但是這樣定義還有一個漏洞,如果在A普通public繼承B的基礎上再定義:
class D:public A{};
你會發現D也是可以實例化的,那麼相當於間接public繼承了B。這顯然不是我們想要的,所以,正確的做法是(完整代碼):
class A;
class B
{
private:
B()
{
}
friend class A;
};
class A:virtual public B{}; //A is the one we're looking for
也就是說要做到三步:
1)將你B的相關構造函數放入private區域
2)聲明子類A爲B的友元
3)定義A爲virtual public繼承B
這樣創建的代碼的效果是:
B不能被繼承也不能被實例化
A可以被實例化,但是不能被繼承
所以,最後創建出來的A纔是真正我們想要得到的對象
“A可以被實例化,但是不能被繼承”爲什麼不能被繼承???
====================================
確切地說,A可以被繼承,但是繼承了A的類不能被實例化(那這個類也就沒用了)。假設有
class E:public A{};
則實例化E時:
E e;
系統將報告無法進入B的私有成員聲明而無法通過編譯。
這是因爲 A是 virtual 繼承 B的,所以,E再繼承A的時候,需要由E去調用B的構造函數,但是E不是B的友元,所以無法編譯通過
但是如果A不是virtual繼承B的,那麼E再繼承A時,構造函數的調用情況是E調用父類A的構造函數,A再調用A的父類B的構造函數,而A是其父類B的友元,所以這一串調用能夠順利進行。