1

これは基本的な概念の質問です。Baseから継承するDerivedクラスがあり、新しいDerivedオブジェクトをインスタンス化する場合、そのBaseオブジェクトを選択した特定のBaseオブジェクトに設定して、すべての呼び出しベースクラスメソッドがこの特定のベースオブジェクトにリダイレクトされるようにできますか?

このようなもの:

class Base
{
protected:
    string name;
public:
    Base(string n) { name = n}
    void doSomething(){cout << name << "\n";}
};

class Derived : public Base
{
public:
     Derived(string n) : Base(n) {}

int main()
{
    Derived* d = new Derived("original base"); //create a derived
    d->doSomething(); // prints "original base"
    Base* rB = new Base("replacement base"); // create a new base object
    ((Base*) d) = rB; // replace the base object of d with a new one (pretend code)
    d->doSomething(); // prints "replacement base"

    return 0;
}

私のスキルレベルは低いので、その単純なコードであらゆる種類のエラーを犯したと確信していますが、それは単なるアイデアです。

これはC++で可能ですか?派生した情報をオブジェクトから切り取ることができるので、継承のチェーン内のコンポーネントを分離して置き換えることができますか?

なぜ私はこれをしたいのですか?

ミックスインユリを考えてみましょう:(ここでも、構文エラーを許してください)

template <class T> class MyMixin : public T
{
public:
    MyMixin(T desiredBaseObject)
    { 
        // do something to set the desired base 
        // object of this class to desiredBaseObject.
    }
};

RandomClass1 dog(int i = 0);  
RandomClass2 cat(double i = 0.0);
MyMixin< RandomClass1 > mixin1(dog);
MyMixin< RandomClass2 > mixin2(cat);

この場合、ミックスインのベースオブジェクトを任意のオブジェクトに設定できれば、ミックスインがそれについて何も知る必要なしに、ミックスイン内の任意のパラメーターリストでコンストラクターを使用できます。また、ミックスインは、デコレータ間で共通のインターフェイスを必要とせずに、デコレータのように使用できます。

答えてくれてありがとう。オブジェクトの派生部分を切り取ることができるので、ベース情報と派生情報は別々に存在しているように見えます。誰かがこれについてコメントできますか?私がよく耳にするvtablesのようないくつかの内部テーブルにアクセスして(このタイプのものについては何も知らないので、おそらくこれは当てはまらないかもしれません)、これを達成できますか?

@Benoît

1と4だけが機能するのに、2と3は機能しない理由を説明してください。class Base {protected:std :: string name; public:Base(std :: string n){name = n; }

    virtual void doSomething()
    {
        cout << name << "\n";
    }
};

class Derived : public Base
{
public:
    int x;
    Derived(std::string n) : Base(n)
    {
        x = 5;
    }

    void printX()
    {
        cout << "x = " << x << "\n";
        x++;
    }
};


Derived* d1 = new Derived("original 1");
d1->doSomething();
d1->printX();
Base* rb1 = new Base("new 1");
*static_cast<Base*>(d1) = *rb1;
d1->doSomething();
d1->printX();
cout << "\n\n";

Derived d2 = Derived("original 2");
d2.doSomething();
d2.printX();
Base b2 = Base("new 2");
static_cast<Base>(d2) = b2;
d2.doSomething();
d2.printX();
cout << "\n\n";

Derived d3("original 3");
d3.doSomething();
d3.printX();
Base b3("new 3");
static_cast<Base>(d3) = b3;
d3.doSomething();
d3.printX();
cout << "\n\n";

Derived d4("original 4");
d4.doSomething();
d4.printX();
Base b4("new 4");
*static_cast<Base*>(&d4) = *&b4;
d4.doSomething();
d4.printX();
cout << "\n\n";

これは印刷されます:

元の1x=5新しい1x= 6

オリジナル2x=5オリジナル2x= 6

オリジナル3x=5オリジナル3x= 6

元の4x=5新しい4x= 6

なぜこれはポインターを使用する場合にのみ機能するのですか?

4

7 に答える 7

3

なぜこれを実行したいのか疑問はありませんが、継承によってISAの関係が壊れない限り、完全に安全です(たとえば、DerivedはBaseの制限されたサブセットです。たとえば、Squareは1つしかサイズ変更できないため、Rectangleではありません。長方形の寸法ですが、正方形では不可能です)。

*static_cast<Base*>(d) = *rB;

(参照でも機能します)

または、小さな関数を書くことができます(これを行う関数がたくさんあります):

template<typename T>
T& assign(T& to, const T& from)
{
  return to = from;
}

assign<Base>(*d, *rB);

とにかく、operator=をオーバーロード/再定義するたびにこれを行います

Derived& operator=(const Derived& other)
{
  // prettier than the cast notation
  Base::operator=(other);

  // do something specific to Derived;
  this->name += " (assigned)";

  return *this;
}
于 2011-06-21T22:03:19.077 に答える
3

いいえ。これを行う必要がある場合は、継承ではなく構成を使用する必要があります。

(私はより一般的な質問に答えています-文字列を変更したいという特定のケースではname、派生クラス内から変更することができます)

于 2011-06-21T19:53:57.477 に答える
1

継承と構成を組み合わせることができます。

class A {
    string name;
public: A(const char* s) : name(string(s)) {}
        virtual void m() { cout << name << endl; }
};

class B : A {
public:
    B(const char* s) : A(s), a(0) {}
    void m() { if (a) a->m(); else A::m(); }
    A* a;
};

int main() {
    B b("b");
    b.m(); // prints b
    b.a = new A("a");
    b.m(); // prints a
}
于 2011-06-21T20:29:46.967 に答える
1

継承=IS A関係。

構成=HAS A関係。

インスタンスを設定できるタイプAのオブジェクトを持つクラスを記述しています。したがって、構成を使用する必要があります-タイプA
のメンバーを保持するクラスを作成します

于 2011-06-21T20:02:02.043 に答える
1

継承は、オブジェクトではなく、タイプのプロパティです。タイプ「Derived」はタイプ「Base」から継承します。タイプ「Derived」( )のオブジェクトを作成できます。また、タイプ「Base」のオブジェクトを作成することもできます(禁止されていない限り)が、これらのオブジェクトはそれぞれ、「交換可能なパーツ」のない完全な本格的なオブジェクトです。Derived x;Base y

型継承のポイントは、型「Derived」のオブジェクトを、型「Base」のオブジェクトであるかのように扱うことができるということです(参照またはポインタで参照する場合)。つまり、関数がある場合です。void foo(Base & b);、その後、を呼び出すことができますfoo(x)。ただし、「ベース」から継承されたfoo部分にしかアクセスできません!x

于 2011-06-21T20:11:04.627 に答える
0

いいえ、それはできません。

(少なくとも)いくつかのオプションがあります:

  • Derived結合する2つのオブジェクトからのパラメーターの混合によってパラメーター化された新しいオブジェクトを作成します。
  • クラス内にいくつかのsetterメソッドを作成しますBase。これにより、その存続期間の後半でパラメーター/状態を変更できます。
于 2011-06-21T19:56:28.197 に答える
0

いいえ。

なぜあなたはこれをしたいのですか?2つの派生物がまったく同じベースを持つことになっている場合(一方の派生物による変更がもう一方の派生物に表示されるように)、継承ではなく、この構成を作成するために、各派生物にベースへのある種のポインターが必要です。

Derived's Baseのデータを変更したい場合は、Baseのコピー代入演算子のように、それを行う関数を記述します。

または、BaseとDerivedを取得し、BaseからBase情報を取得し、DerivedからDerived情報を取得するDerivedの新しいコンストラクターを作成することもできます。

于 2011-06-21T20:00:47.013 に答える