2009-04-30 44 views
3

我們有一個限制,即一個類不能作爲超過7個類的基類。 有沒有辦法在編譯時強制執行上述規則?在編譯時將繼承限制爲期望數量的類

我知道Andrew Koenig的Usable_Lock技術可以防止類被繼承,但只有當我們嘗試實例化類時它纔會失敗。這不能在派生自己的時候完成嗎?

允許基類知道誰是它的子女。所以我想我們可以聲明一個朋友 類的組合並封裝它們來執行這個規則。假設我們嘗試這樣的事情

class AA { 
    friend class BB; 
    private: 
     AA() {} 
     ~AA() {} 
}; 

class BB : public AA { 

}; 

class CC : public AA 
{}; 

CC類的派生會生成一個編譯器警告abt無法訪問的dtor。然後,我們可以使用編譯器調整(例如將所有警告標記爲錯誤)來標記 等警告,但我不想依賴這種技術。

的另一種方式,但對我來說看起來相當笨拙是: -

class B; 

class InheritanceRule{ 
    class A { 
    public: 
     A() {} 
     ~A() {} 
    }; 
    friend class B; 
}; 

class B { 
public: 
    class C : public InheritanceRule::A 
    {}; 
}; 


class D : public InheritanceRule::A{}; 

d類的派生將被標記爲編譯器錯誤,意思是派生類應該B.內部派生的所有類這將允許至少檢查從A類派生的類的數量,但不會阻止任何人增加更多。

這裏有誰有辦法嗎?如果基地級別不需要知道誰是其子女,那更好。

注意:充當基類的類本身可以被實例化(它不是抽象的)。

由於提前,

EDIT-1:按照從jon.h註釋,稍微修改

// create a template class without a body, so all uses of it fail 
template < typename D> 
class AllowedInheritance; 

class Derived; // forward declaration 
// but allow Derived by explicit specialization 
template<> 
class AllowedInheritance< Derived> {}; 

template<class T> 
class Base : private AllowedInheritance<T> {}; 

// privately inherit Derived from that explicit specialization  
class Derived : public Base<Derived> {}; 

// Do the same with class Fail Error 
// it has no explicit specialization, so it causes a compiler error 
class Fail : public Base<Fail> {}; // this is error 

int main() 
{ 
    Derived d; 

    return 0; 
} 
+4

爲什麼選擇7? – Shog9 2009-04-30 05:22:03

+0

>注意:充當基類的類本身可以被實例化(它不是抽象的)。 等等,認真嗎?你有一個關於子類的數量的任意規則,這沒有任何可以想象的目的,但不是關於使抽象的基礎,這是什麼? – tpdi 2009-04-30 05:38:49

+0

@ Shog9:我不知道爲什麼它只有7,它可能是我認爲的任何數字。項目建築師不喜歡nos> 7我猜:-) @tpdi:候選基類可能並不總是一個iterface。 老實說,我也不明白這背後的概念,除了放牧不馴的遺傳承認程序員,但我會在稍後處理。目前我正在嘗試查看是否有任何解決方案。 – Abhay 2009-04-30 05:43:28

回答

2

我累了的廢話,只能勉強眼睛都睜不開,所以有可能是一個更優雅的方式來做到這一點,我當然不會贊同這一古怪的想法,一個基地應該有至多七個子類。從jon.h

// create a template class without a body, so all uses of it fail 
template < typename D, typename B> class AllowedInheritance; 


class Base {}; 
class Derived; // forward declaration 

// but allow Derived, Base by explicit specialization 

template<> class AllowedInheritance< Derived, Base> {}; 

// privately inherit Derived from that explicit specialization  
class Derived : public Base, private AllowedInheritance<Derived, Base> {}; 


// Do the same with class Compiler Error 
// it has no explicit specialization, so it causes a compiler error 
class CompileError: public Base, 
    private AllowedInheritance<CompileError, Base> { }; 

//error: invalid use of incomplete type 
//‘struct AllowedInheritance<CompileError, Base>’ 


int main() { 

    Base b; 
    Derived d; 
    return 0; 
} 

評論:

這是如何停止例如:類故障:公共基礎{}; ? \

它沒有。但是,OP的最初例子也沒有。

To the OP: your revision of my answer is pretty much a straight application of Coplien's "Curiously recurring template pattern"]

我會考慮爲好,但與這個問題有一個derived1 : pubic base<derived1>derived2 : pubic base<derived2>之間沒有繼承關係,因爲base<derived1>base<derived2>是兩個完全不相關的類。

如果你唯一關心的是繼承的實現,這是沒有問題的,但是如果你想繼承接口,你的解決方案會打破這個。

我認爲有一種方法可以同時獲得繼承和更乾淨的語法;正如我所提到的,當我編寫解決方案時,我感到非常疲倦如果沒有別的,通過在您的示例中將RealBase作爲基類的基類是一個快速修復。

可能有很多方法可以清除它。但我想強調的是,我同意markh44:即使我的解決方案更清晰,我們仍然混淆了代碼以支持一條毫無意義的規則。只是因爲這可以做到,並不意味着它應該。

如果有問題的基類是十歲,太脆弱而無法繼承,真正的答案是解決它。

+0

+1,絕對更清潔。雖然我將不得不與這個規則的架構師一起檢查是否允許使用模板:-) – Abhay 2009-04-30 06:30:47

2

大量的各種靜態代碼分析工具提供有關繼承層次結構信息。與其試圖在代碼中處理它,我會研究一個可以爲繼承層次結構設置一些規則的工具,如果沒有遵循這些規則,就會使構建失敗。可能花費一點點$,你可能不得不寫一個自定義規則(我已經看到了繼承深度,但不像你想要的那樣繼承「寬度」)。但是,從長遠來看,我認爲這是你最好的選擇。

評論:我用Coverity取得了一些成功。有點花。有several good SO threads可能有更好的選擇。

+0

感謝您的建議。你可以引用那些給你一個很好的經驗w.r.t靜態代碼分析的工具嗎?我會檢查一樣的。 – Abhay 2009-04-30 05:50:38

4

對不起,我不知道如何使用編譯器強制執行任何此類限制。

就我個人而言,我不打算試圖強制規則進入代碼本身 - 你在與代碼正在做的事情無關的代碼混亂 - 這不是乾淨的代碼。

與其跳過箍環,我試圖讓規則放鬆。相反,它應該是一個指導方針,必要時可以打破,並與團隊中的其他人達成一致。

當然,我不知道你在做什麼,所以規則可能是適當的,但一般來說它可能不是。

任何編程「規則」,說你絕不能做x或者你必須總是做y幾乎總是錯的!在那裏注意「幾乎」這個詞。

有時你可能需要 7個以上的派生類 - 那你做什麼?跳過更多的籃球。另外,爲什麼是7?爲什麼不是6或8?這太隨意了 - 這是一個糟糕的規則的另一個跡象。

如果你必須這樣做,正如JP所說,靜態分析可能是更好的方法。

1

您可能可以使用類似GCC-XML的東西來代替使用g ++編譯器前端分析C++源代碼,並生成XML輸出,而不是使用斷言混淆代碼。我期望開發一個工具來分析這個輸出並檢查是否違反規則是合理的直截了當;這可以與源代碼簽入集成。

順便說一句,有基類知道他們的後代違反Open-Closed Principle,這意味着它實際上削弱了一般的OO編程的用處。 主要原因用於將代碼分離到基類和子類中,以便基類不必知道關於它的子類 - 這使安裝後交付插件包成爲可能。