1

フィールドキーとクラスAまたはBを持つとしましょう。このクラスのコンストラクターの引数は、文字の配列です。コンストラクタの疑似コードは最初の char を見て、それが 0x00 に等しい場合はクラス A オブジェクトを作成し、それ以外の場合はクラス B オブジェクトを作成します - どちらのクラスも引数として char の配列を取ります。

とにかく、私はこの実装をシンプルに保ちたいと思っています。本当に必要でない限り、boost::Variant を使用したくありません。また、このような sth を実装したくありません。「バリアント」クラスの実装は 、テンプレート プログラミングに慣れておらず、問題が次のようになる可能性があるためです。より簡単な方法で実装されます。

4

1 に答える 1

2

POD タイプの場合は、 (ただし、割り当てunionタイプを共用体は覚えていないため、これも個別に保存します)。これは、POD 以外のタイプでは機能しません。主な理由は、C++ が構築時に作成する必要があるか、共用体の削除時に削除する必要があるかを認識していないためです。

ただし、共用体を使用して、実際の型へのポインターを保持できます。次に、自分で構築と削除を気にする必要があります。

このポインタ共用体をラップし、便利なインターフェイスを追加する、このようなものを作成できます。詳細な説明はコメントに書かれています:

class EitherAorB {
    // We have to remember what we actually created:
    enum Which {
        A_Type,
        B_Type
    } m_which;

    // We store either a pointer to an A or to a B. Note that this union only
    // stores one pointer which is reused to interpret it as an A*, B* or void*:
    union {
        A *a;
        B *b;
        void *untyped; // Accessing the same pointer without looking at the type
    } m_ptr;

    // Additional stuff you want to store besides A and B
    const char *m_key;

public:
    EitherAorB(const char *key) {
        // Decision: Which type do we want to create?
        m_which = key[0] == 0 ? A_Type : B_Type;
        // Create the type (the cast to void* make the pointer "untyped"):
        m_ptr.untyped = m_which == A_Type ? (void*)new A() : (void*)new B();

        // Store additional stuff
        m_key = key;
    }
    ~EitherAorB() {
        // Since we stored the actual contents outside and point to them,
        // we have to free the memory. For this, we have to care about the
        // type again, so the correct destructor will be chosen. Deleting
        // the untyped pointer won't work here.
        if (m_which == A_Type) delete m_ptr.a;
        if (m_which == B_Type) delete m_ptr.b;
    }

    // These two functions can be used to query which type is stored.
    bool hasA() const {
        return m_which == A_Type;
    }
    bool hasB() const {
        return m_which == B_Type;
    }

    // These two functions can be used to query the pointers to the actual types.
    // I made them return a null pointer if the wrong getter was used.
    A *getA() {
        return m_which == A_Type ? m_ptr.a : 0;
    }
    B *getB() {
        return m_which == B_Type ? m_ptr.b : 0;
    }
}

のインスタンスをコピーすると、この実装ではメモリが不足することに注意してくださいEitherAorB。これを修正するには、コピーを無効にする (コピー コンストラクターと代入演算子をプライベートにするか、C++11 で を使用して無効にする= delete) か、コピー コンストラクターと代入演算子を実装して、ポインティを深くコピーします。


あなたは、テンプレート プログラミングに慣れていないと言いました。この実装をテンプレート化することは難しくありません。template<typename A, typename B>クラス定義全体の前に置くだけです。その後、箱から出してすぐに動作するはずです。.cppただし、この場合、ファイル内の実装を移動しないでください。私が書いたようにインラインのままにしておくのが最善です。

次に、AandBは型ではなく、クライアント コードで型を割り当てるプレースホルダーです。次に、tempalte クラスの名前を justEitherに変更すると、型名はEither<This, That>.

于 2013-05-10T10:34:52.623 に答える