8

私は単純な古い CRPT を持っています (アクセス制限に気を取られないでください - 問題はそれらについてではありません):

 template<class Derived>
 class Base {
     void MethodToOverride()
     {
        // generic stuff here
     }
     void ProblematicMethod()
     {
         static_cast<Derived*>(this)->MethodToOverride();
     } 
 };

これは通常、次のように使用することを目的としています。

 class ConcreteDerived : public Base<ConcreteDerived> {
     void MethodToOverride()
     {
        //custom stuff here, then maybe
        Base::MethodToOverride();
     }
 };

今それは私をstatic_cast悩ませます。(アップキャストではなく) ダウンキャストが必要なので、明示的なキャストを使用する必要があります。現在のオブジェクトが実際に派生クラスであるため、妥当なすべてのケースでキャストは有効です。

しかし、どうにかして階層を変更し、キャストが無効になったらどうしますか?

この場合、明示的なダウンキャストが有効であることをコンパイル時にチェックすることはできますか?

4

5 に答える 5

5

At compile-time you can only check the static types, and that's what static_cast already does.

Given a Base*, it is only, and can only be, known at run-time what its dynamic type is, that is, whether it actually points to a ConcreteDerived or something else. So if you want to check this, it has to be done at runtime (for example by using dynamic_cast)

于 2011-05-06T06:47:04.147 に答える
4

安全性を高めるために、保護されたコンストラクターをBaseに追加して、そこから何かが派生していることを確認できます。次に、唯一の問題は本当に愚かなことです:

class ConcreteDerived : public Base<SomeOtherClass>

しかし、それは最初のコードレビューまたはテストケースによって捕らえられるべきです。

于 2011-05-06T07:07:58.530 に答える
3

@Bo Perssonが言ったことを拡張するために、たとえばBoost.TypeTraitsまたはC ++ 0x / 11を使用して、前述のコンストラクターでコンパイル時チェックを実行できます<type_traits>

#include <type_traits>

template<class Derived>
struct Base{
  typedef Base<Derived> MyType;

  Base(){
    typedef char ERROR_You_screwed_up[ std::is_base_of<MyType,Derived>::value ? 1 : -1 ];
  }
};

class ConcreteDerived : public Base<int>{
};

int main(){
  ConcreteDerived cd;
}

Ideoneの完全な例。

于 2011-05-06T07:27:45.590 に答える
2

コンパイル時にCRPTの正しさをチェックする方法があるようです。

Baseを抽象化する(Baseに純粋仮想メソッドを追加する)ことにより、Baseインスタンスが派生インスタンスの一部であることを保証します。

すべてのBaseコンストラクターをプライベートにすることで、Baseからの望ましくない継承を防ぐことができます。

DerivedをBaseのフレンドとして宣言することにより、CRPTで期待される唯一の継承を許可します。

この後、CRPTダウンキャストは正しくなるはずです(何かがベースから継承され、この「何か」は派生のみであり、他のクラスではない可能性があるため)

おそらく実用的な目的のために、最初のステップ(Baseを抽象化する)は冗長です。これは、DerivedがBase階層のどこかにあることをstatic_castが保証するためです。これは、Derivedが(CRPTが期待するように)継承されている場合にのみエキゾチックなエラーを許可しますBase <Derived> が、同時にDerivedはBase <derived> Derivedコードのどこかに(継承なしで)別のインスタンスを作成します(それは友人であるため可能です)。しかし、誰かがそのようなエキゾチックなコードを誤って書いたのではないかと思います。

于 2012-06-28T10:22:25.803 に答える
1

以下のようなことをすると:

struct ConcreteDerived : public Base<Other>  // Other was not inteded

class(派生またはベース)のオブジェクトを作成できます。ただし、関数を呼び出そうとすると、static_castのみに関連するコンパイル エラーが発生します。私見では、すべての実用的なシナリオを満たします。

質問を正しく理解していれば、答えはあなたの質問自体にあると思います。:)

于 2011-05-06T07:54:30.760 に答える