1

私の意図はCBaseClass、とりわけ type の一部のメンバーへのコンテナーとして機能する基本クラスを持つことCBaseMemberです。CDerivedClass : public CBaseClass次に、を保持する a を導出しますCDerivedMember : public CBaseMember

へのポインターを使用してオブジェクトでCBaseMember初期化することはできません。これは、多重継承の状況であり、実装とは無関係であるが に表示する必要がある追加のインターフェイス (純粋な抽象基本クラス) があるためです。たくさんのダーティ キャスティングは避けたいものです。CDerivedMemberCDerivedClassCDerivedMemberCBaseClassCDerivedClass

この問題に対する私の解決策はCBaseClass、次のようなテンプレートを作成することでした。

//declaration
template <class Member>
CBaseClass
{
protected:
    virtual void GenericMethod();
    virtual void VirtualMethod() = 0;

    Member* member;
};

//definition
template <class Member>
void CBaseClass<Member>::GenericMethod()
{
    member->SomeMemberMethod();
}

そして、次CDerivedClassのように継承します。

//declaration
CDerivedClass : public CBaseClass<CDerivedMember>
{
protected:
    virtual void VirtualMethod();
};

//definition
void CDerivedClass::VirtualMethod()
{
    member->SomeDerivedMethod();
}

予想通り、これは機能しません (CBaseClass<CDerivedMember>::GenericMethod()明らかな理由で未解決です) が、残念ながら、意図したとおりにコードを変更する方法がわかりません。

それらがどのように適切に行われるかを説明してください。または、私の問題に対する別の解決策を提案してください。

ありがとう!

4

2 に答える 2

0

class提供したスニペットが機能するため (型の宣言にキーワードを追加した場合)、テンプレートを削除したいと思われます。

CBaseMember*からへのダウンキャストを避けたい場合はCDerivedMember*、動的バインディングと共分散を使用して状況にアプローチできます

class CBaseClass {
  private:
    CBaseMember* const baseMember;
  protected:
    virtual CBaseMember* member() const {
    //      ^^^^^^^^^^^
      return baseMember;
    }
    /* everything else you need here. Just never ever access `baseMember` directly */
};
class CDerivedClass : public CBaseClass {
  private:
    CDerivedMember* const derivedMember;
  protected:
    virtual CDerivedMember* member() const {
    //      ^^^^^^^^^^^^^^
      return derivedMember;
    }
    /* everything else you need here. Just never ever access `derivedMember` directly */
};

ただし、これは、セッターでこのトリックをプルできないため、メンバーを別の場所に変更しない場合にのみ機能virtual void CBaseClass::member(CBaseMember*)virtual void CDerivedClass::member(CDerivedMember*)ます。

baseMember使用されることはありませんが、ポインターは常に持ち歩いていることに注意してくださいCDerivedClass。したがって、メモリが重要な場合、これは実行できない可能性があります.

于 2012-04-12T11:00:01.460 に答える
0

ダーティな型キャストを 1 か所に保持し、クラスにカプセル化することができます。したがって、それはもう本当に汚れていません。

class CBaseMember {
public:
    virtual void SomeMemberMethod(){}
};

class CDerivedMember : public CBaseMember {
public:
    virtual void SomeMemberMethod() { /* do other stuff */ }
    virtual void SomeDerivedMethod() {}
};

//declaration
class CBaseClass
{
protected:
    virtual void GenericMethod();
    virtual void VirtualMethod() = 0;

    CBaseMember* member;
    virtual CBaseMember * getMember() {
    return member;
    }
};

//definition
void CBaseClass::GenericMethod()
{
    getMember()->SomeMemberMethod();
}

//declaration
class CDerivedClass : public CBaseClass
{
protected:
    virtual void VirtualMethod();
    virtual CDerivedMember * getMember() {return static_cast<CDerivedMember *>(member);}
};

//definition
void CDerivedClass::VirtualMethod()
{
    getMember()->SomeDerivedMethod();
}

getMember()要約すると、派生クラスのメソッド内で汚い型キャストを行います。その時点で、メンバーのタイプがCDerivedMemberとにかくであることを確認する必要があります。したがって、持っているポインターが型であることがわかっている限り、型キャストせずCDerivedClassにアクセスできます。CDerivedMemberポインターにフォールバックする必要がある場合は、そのメンバーにアクセスしCBaseClassているときに自然に にフォールバックします。CBaseMember

于 2012-04-12T10:28:01.350 に答える