2009-04-30 10 views
3

クラスが7つ以上のクラスのベースクラスとして動作できないという制限があります。 コンパイル時に上記の規則を適用する方法はありますか?コンパイル時に継承を望ましいクラス数に制限する

私はAndrew KoenigのUsable_Lock技法が、クラスが継承されないようにすることを知っていますが、クラスをインスタンス化しようとすると失敗するだけです。これは自分自身を派生させるときにできないのですか?

ベースクラスは、誰がその子であるかを知ることができます。だから私たちは友達の組み合わせを宣言することができると思います クラスと、このルールを強制するためにカプセル化します。このようなものを試してみることにしましょう。012 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:コメント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

+0

>注:基本クラスとして機能するクラス自体は、インスタンス化することもできます(抽象クラ​​スではありません)。 お待ちください、真剣に?あなたは考えられる目的を果たさないサブクラスの数について任意のルールを持っていますが、ベースを抽象化するのではありません。 – tpdi

+0

@ Shog9:なぜそれが7だけであるのか分かりません。プロジェクトのアーキテクトはnos> 7のようには思えません:-) @tpdi:候補ベースクラスは常にiterfaceであるとは限りません。 正直なところ、私はこの背後にあるコンセプトを理解していません。それは、不当な継承を嫌うプログラマーを託すことを除いてですが、後で取り上げます。現在、私は解決策があるかどうかを確認しようとしています。 – Abhay

答えて

2

私は気をつけて目を開いているので、おそらくこれを行うためのよりエレガントな方法があります。Baseが最大7つのサブクラスを持つという奇妙な考えを支持しているわけではありません。

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

jon.hからコメント:

どのように例えばこの停止:クラス失敗:公衆基地{}。 ? \

これはありません。しかし、どちらもOPの元の例はありませんでした。

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

私は同様と考えますが、base<derived1>base<derived2>は、2つの完全に無関係のクラスであるため、derived1 : pubic base<derived1>derived2 : pubic base<derived2>の間には継承関係は、ありませんということで問題のです。

唯一の懸念事項は実装の継承ですが、これは問題ありませんが、インターフェースの継承が必要な場合は、ソリューションで問題が解決されます。

私は、両方の継承とより洗練された構文を取得する方法があると思います。私が言ったように、私は私の解決策を書いたとき、私はかなり疲れていました。それ以外の場合は、RealBaseをベースの基本クラスにすることで、簡単に修正できます。

これをクリーンアップする方法はいくつかあります。しかし私はmarkh44に同意することを強調したいと思います。私の解決策はより洗練されていますが、ほとんど意味のないルールをサポートするためにコードを乱雑にしています。これができるからといって、それがあるべきではありません。

問題の基本クラスが10歳であり、脆弱すぎて継承できない場合は、本当の答えはそれを修正することです。

+0

+1、確かにクリーナー。テンプレートが許可されているかどうかは、このルールのアーキテクトに確認する必要があります: – Abhay

+1

これはどのようにして停止しますか? クラス失敗:public Base { }; ? –

+0

私の編集を参照して、正しく指摘しました。しかし、解決策は正しい方向にあり、最初に投稿されたものよりはるかにクリーンです。ありがとう – Abhay

2

多くは継承階層に関する情報を提供します。あなたのコードでそれを試して扱うのではなく、継承階層のいくつかのルールを設定し、それらのルールに従わないとビルドに失敗するツールを調べます。少しコストがかかるかもしれないし、カスタムルールを書く必要があるかもしれません(継承の深さは見てきましたが、あなたが望むような継承 "幅"はありません)。しかし、長期的には、それがあなたの最善の策だと思います。

コメント数:私はCoverityを使用して成功しました。ビット消費量。より良いオプションを持つseveral good SO threadsがあります。

+0

提案していただきありがとうございます。あなたは、静的コード分析にあなたに良い経験を与えてくれたツールを親切に引用できますか?私は同じことを確認します。 – Abhay

4

申し訳ありませんが、私はどのようにコンパイラを使用してそのような制限を実施するのか分かりません。

個人的には、コード自体にルールを強制しようとするのではなく、コードが何をしているのかとは関係のないコードを混乱させています。

フープをジャンプするのではなく、そのルールを緩和しようとします。代わりに、必要に応じて、チームの他の人と合意して破られる可能性のあるガイドラインにする必要があります。

もちろん、あなたがしていることを正確に知ることができないので、ルールになりますが、一般的にはそうではありません。

あなたは決してxをしてはいけないと言っているプログラミングの "ルール"や、常にyをする必要があります。そこに「ほとんど」という言葉があることに注目してください。

場合によっては派生クラス以上が必要です - あなたは何をしていますか?より多くのフープをジャンプします。また、なぜ7?なぜ6か8ではないのですか?それはまったく恣意的です - 貧しいルールのもう一つの兆しです。

もしそれをしなければならないのならば、JPが述べるように、静的解析がおそらく良い方法でしょう。

+0

私はあなたの感想に同意します。プラットフォームごとにコードベースが異なる場合はどうなりますか?すべてのショップが、すべてのプラットフォームでこのようなツールを購入するための財務帯域幅を持っているとは限りません。 また、プロジェクトガイドラインの後に、これを実施できるかどうかを確認しています。私たちはそれが不可欠だと考えています。あなたはそれを軽蔑するかもしれませんが、問題はありません。 明らかに、なぜそれを行う必要があるかという特殊なケースがあります。私たちは、完全な知識なしに使用されているいくつかの*クラスだけのために特別に設計された基本クラスを持っていました。そのコードは、C++ 98よりも前にさかのぼります。特殊なString/Iteratorクラスを想像してみてください。 – Abhay

+0

十分に公正。私は正当な理由があるように聞こえるので、アイデアを軽蔑しません。私はときどき人々を間違った道のりに押しやる不当なルールやガイドラインに遭遇し、これは当初のように聞こえました。アイデアのために – markh44

1

アサーションでコードを乱雑にするのではなく、GCC-XMLのようなものを使用することができます。これは、g ++コンパイラフロントエンドを使用してC++ソースを解析し、XML出力を生成します。私は、この出力を解析してルールの違反をチェックするツールを開発することは合理的に簡単だと思います。これをソースコードのチェックインと統合することができます。

BTWは、その子孫について知っている基本クラスがOpen-Closed Principleに違反しているため、一般的にオブジェクト指向プログラミングの有用性を実証していません。 主な理由ベースクラスとサブクラスにコードを分けるための基本クラスはそのサブクラスについてを知る必要はありません - これはインストール後に提供されるプラグインパッケージのようなものを可能にします。

+0

+1。 Open-Closedイディオムは論争するべきではありませんが、問題のドメインは、いくつかのガイドラインの乱用を防ぐためにコンパイラファイアウォールのようなものでした。このアイデアは、静的なコード分析をしてから、大規模なコードベースや大規模なチームの変更を行うよりも優れていると思います。ありがとう – Abhay

+0

私は、正式な意味でサブタイプ化する以外の理由で継承を使用するのが便利な場合があることに同意します。ほとんどのものと同様に、「あなたがやっていることを知っている限り...」:) –

関連する問題