0

スライスに問題があると思いますが、修正方法がわかりません。実際のプログラムの問題を以下の例にまとめました。

#include <iostream>
#include <vector>
using namespace std;

class Base {
public:
    void Use(void) {
        cout << "Using Base :(\n";
    }
};

class First_Derived : public Base {
public:
    void Use(void) {
        cout << "Using First_Derived!\n";
    }
};

class Second_Derived : public Base {
public:
    void Use(void) {
        cout << "Using Second_Derived!\n";
    }
};

class A {
public:
    vector<Base *> Base_Objects;
};

class B {
public:
    vector<Base *> Base_Objects;
};


int main() {
    // Create and populate A_Object
    A A_Object;
    A_Object.Base_Objects.push_back(new First_Derived());
    A_Object.Base_Objects.push_back(new Second_Derived());

    // Create and populate B_Object with objects in A_Object.Base_Objects
    B B_Object;
    for (vector<Base *>::iterator i = A_Object.Base_Objects.begin(); i != A_Object.Base_Objects.end(); ++i) {
        B_Object.Base_Objects.push_back(*i);
    }

    // Run the Use() function for the first object in B_Object.Base_Objects
    (*B_Object.Base_Objects[0]).Use();

    // Get command terminal to pause so output can be seen on Windows
    system("pause");
    return 0;
}

出力はですUsing Base :(が、私は期待していUsing First_Derived!ました。問題は、First_Derivedオブジェクトがベクターに格納されると、型に変換されるため、そのBase_Objects固有の機能が失われることだと思いますか? これに対する解決策はありますか?「オブジェクト スライスとは何ですか?」に記載されている解決策のいくつかを適用しようとしました。しかし、私はそれらを正しく適用しているとは思いません。Use()Base

4

2 に答える 2

3

コメントを回答に移動

あなたの問題は、スライスではなく非仮想関数 (メソッドの隠蔽) を使用していることです。

子クラスで関数を定義すると、親クラスの同じメソッドの実装が「隠蔽」されます。

あなたがしたいことは、メソッドを仮想として宣言することです:

class Base {
public:
    virtual void Use(void) {
        cout << "Using Base :(\n";
    }
};

class First_Derived : public Base {
public:
    virtual void Use(void) {
        cout << "Using First_Derived!\n";
    }
};

class Second_Derived : public Base {
public:
    virtual void Use(void) {
        cout << "Using Second_Derived!\n";
    }
};

この件について話している間、おそらく仮想デストラクタも宣言したいと思うでしょう。

親クラスに割り当てられたスペースに子クラスを格納しようとすると、スライスが発生します。この場合、親クラスの値に十分なスペースしかないため、子の値は取り残されます。おかしなことに、これは通常、メンバーにアクセスしようとした場合にのみ表示されます...仮想関数呼び出しは引き続き呼び出されます (vtable は正しいメソッド呼び出しを指します)。スライスすると、スタックとヒープの破損エラーが発生し、値が奇妙に見えます...いわば「未定義の動作」ですが、それでもクラス内の正しい仮想関数を呼び出します!

于 2014-10-22T19:50:00.847 に答える
0

これはスライスの問題ではありません。あなたはそうするつもりだったと思いますUsevirtual、そうではありません。

于 2014-10-22T19:47:41.703 に答える