コンパイル時に継承を目的のクラス数に制限する
-
03-07-2019 - |
質問
1つのクラスが7つを超えるクラスの基本クラスとして機能できないという制限があります。 コンパイル時に上記のルールを強制する方法はありますか?
Andrew Koenigのクラスが継承されないようにするUsable_Lockテクニックは知っていますが、クラスをインスタンス化しようとしたときにのみ失敗します。自分自身を導出するときにこれを行うことはできませんか?
基本クラスは、その子が誰であるかを知ることができます。友人の組み合わせを宣言できると思います クラスを作成し、それらをカプセル化して、このルールを適用します。このようなことを試してみましょう
class AA {
friend class BB;
private:
AA() {}
~AA() {}
};
class BB : public AA {
};
class CC : public AA
{};
クラスCCの派生は、コンパイラに警告abt inaccessible 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;
}
解決
私はがらくたに疲れていて、ほとんど目を開けられないので、おそらくもっとエレガントな方法があるでしょう。そして、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からのコメント:
たとえば、これはどのように停止しますか。class Fail:public Base {}; ? \
そうではありません。しかし、その後、OPの元の例も行われませんでした。
OPへ:私の回答の改訂版は、Coplienの<!> quotをそのまま適用したものです。 ;不思議な繰り返しテンプレートパターン<!> quot; ]
も考えましたが、derived1 : pubic base<derived1>
とderived2 : pubic base<derived2>
は完全に無関係な2つのクラスであるため、base<derived1>
とbase<derived2>
の間に継承関係がないという問題があります。
実装の継承のみが懸念される場合、これは問題ありませんが、インターフェイスの継承が必要な場合、ソリューションはそれを破ります。
継承とより簡潔な構文の両方を取得する方法があると思います。前述したように、ソリューションを作成したときはかなり疲れていました。それ以外の場合は、RealBaseを例のBaseの基本クラスにすることで簡単に修正できます。
これをクリーンアップする方法はおそらくいくつかあります。しかし、markh44に同意することを強調したいと思います。たとえ私のソリューションがよりクリーンであっても、ほとんど意味のないルールをサポートするためにコードが散らかっています。これができるからといって、そうすべきだという意味ではありません。
問題の基本クラスが10年前で、継承するには脆弱すぎる場合、本当の答えはそれを修正することです。
他のヒント
申し訳ありませんが、コンパイラを使用してこのような制限を強制する方法はわかりません。
個人的には、コード自体にルールを強制しようとすることはありません-あなたはコードがしていることとは関係のないものでコードを乱雑にしている-それはきれいなコードではありません。
フープをジャンプするのではなく、そのルールを緩和しようと思います。代わりに、必要に応じて破られ、チームの他のメンバーと合意できるガイドラインにする必要があります。
もちろん、あなたが何をしているのか正確にはわからないので、ルールは 適切かもしれませんが、一般的にはおそらくそうではありません。
任意のプログラミング<!> quot; rule <!> quot;つまり、xを実行してはいけない、または常にyを実行する必要があるということは、ほとんど常に間違っています単語<!> quot; almost <!> quot;に注意してください。そこで。
7つ以上の派生クラスを必要にする場合があります。より多くのフープをジャンプします。また、なぜ7ですか?なぜ6または8ではないのですか?それは非常に-意的です-貧しいルールのもう一つの兆候。
やらなければならない場合は、JPが言うように、静的解析がおそらくより良い方法です。
さまざまな静的コード分析ツールの多くは、継承階層に関する情報を提供します。コードでそれを試して処理するのではなく、継承階層のいくつかのルールを設定し、それらのルールに従わないとビルドに失敗する可能性のあるツールを検討します。少し費用がかかる場合があり、カスタムルールを作成する必要があるかもしれません(継承の深さは見たことがありますが、継承<!> quot; breadth <!> quot;は好きではありません)。しかし、長期的には、それが最善の策だと思います。
コメントごと: Coverity を使用して、ある程度成功しました。少々費用がかかります。より良いオプションがあるいくつかの優れたSOスレッドがあります。
アサーションでコードを乱雑にするのではなく、 GCC-XMLのようなものを使用できる場合があります。g++コンパイラフロントエンドを使用してC ++ソースを解析し、XML出力を生成します。この出力を解析し、ルールの違反をチェックするツールを開発することは合理的で簡単だと思います。これは、ソースコードチェックインと統合できます。
ところで、基底クラスに子孫について知ってもらうと、オープンクローズド原則に違反します、これは実際にオブジェクト指向プログラミング一般の有用性を実際に下回ります。コードを基本クラスとサブクラスに分離する主な理由は、基本クラスがそのサブクラスについて知る必要がないようにするためです。インストール。