2

より良いインターフェイスを提供するために、いくつかの自動生成されたクラスのラッパーを作成しています。問題を示すために簡単な例を書きました。

クラスXのオブジェクトへのポインターを持つクラスAがあり、クラスYのオブジェクトへのポインターを持つクラスB(Aを継承)があります(Xを継承します)。

X と Y へのポインターを格納する最善の方法がわからないことを除けば、それで問題ありません。クラス A と B のオブジェクトのコレクションを、それらがすべて A であるかのように (X へのポインターを使用して) 操作できる必要があります。私が必要とするのはそれだけです)、これは以下の私の例でうまくいきます。

私の実際の質問は、クラス X ではなくクラス Y オブジェクトを操作する必要があるクラス B のケースをどのように処理するのが最善かということです。この変数を使用するたびに繰り返しキャストし、作成した A を継承するクラスごとに異なる名前 (getY など) のメソッドを定義しなければならないのは、ぎこちなく感じます。getY を呼び出す必要がある doStuff のような多くのメソッドが存在する可能性があります。

class X {
private:
    int i;
public:
    X(int i) : i(i) {}
    int getI() {
        return i;
    }
};

class Y : public X {
private:
    int j;
public:
    Y(int i, int j) : X(i), j(j) {}
    int getJ() {
        return j;
    }
};

class A {
protected:
    X* x;
public:
    A(X* a) : x(a) {}
    X* get() {
        return x;
    }
};

class B : public A {
public:
    B(Y* y) : A(y) {}
private:
    //I could create a new function for each class like class B
    Y* getY() {
        return (Y*)x;
    }
public:
    void doStuff() {
        Y* y = getY();
        y->getJ();
        std::cout << "J: " << y->getJ() << cout::endl;
    }
};

メインから抜粋:

X* x = new X(5);
Y* y = new Y(5,6);
B b(y);
b.doStuff();

私に発生する1つの代替案は、クラスBIを構築するときに、Xに設定されている場所と同じ場所を指すタイプY変数のポインターを初期化できるということです。私のポインターがconstである限り、それは異なるものを指す 2 つの参照。

どんなアイデアでも大歓迎です。

ありがとう。

4

2 に答える 2

1

まず最初に、A と B の間の継承関係を壊します。共通のインターフェースがあるとあなたは言うので、このインターフェースを定義することから始めます。

class ILibraryWrapper {
public:
    virtual X * get() = 0;
};

A と B は多くのコードを共有していると思います (したがって、継承関係があります)。次に、インターフェイスを実装するテンプレート クラスを定義し、共通部分を定義します。

template <class T> class LibraryWrapper : public ILibraryWrapper {
protected:
    T * pointer;

public:
    LibraryWrapper( T * value ) : pointer( value ) {}

    virtual X * get() override { return static_cast<X *>( this->pointer ); }
};

最後に、A と B を次のように定義します。

class A : public LibraryWrapper<X> {
public:
    A( X * value ) : LibraryWrapper( value ) {}
};

class B : public LibraryWrapper<Y> {
public:
    B( Y * value ) : LibraryWrapper( value ) {}

    void doStuff() {
        std::cout << "J: " << this->pointer->getJ() << cout::endl;
    }
};

事実上、すべてのコードで ILibraryWrapper ポインターまたは参照を処理する必要があります。一部のコードがラップされたオブジェクトの具象型を絶対に知っている必要がある場合は、動的キャストを行うことができます。

auto wrapper = dynamic_cast<LibraryWrapper<Y> *>( object );
if( wrapper != nullptr ) {
    // ...
}

しかし、一般的に言えば、必要なすべての機能を ILibraryWrapper インターフェイスで提供することをお勧めします。

于 2013-01-25T14:54:13.423 に答える
0

Y が X から派生し、B が A から派生する限り、これは簡単です。

仮想関数は、戻り値の型が多態的である限り、戻り値の型によって異なる場合があります。A で以下を実装します。

virtual X* Get() const { return x; }

B には次のように記述します。

virtual Y* Get() const { return static_cast< Y* >( A::Get() ); }
于 2013-01-25T15:05:50.400 に答える