在传染媒介内的类切片

时间:2014-10-22 19:44:35

标签: c++ object-slicing

我相信我有一个切片问题,我不知道如何解决它。我已将实际程序中的问题总结为下面的示例。

#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()函数,因为它会转换为{{1}键入?这个问题有方法解决吗?我试图应用What is object slicing?中列出的一些解决方案,但我不相信我正确应用它们。

2 个答案:

答案 0 :(得分:3)

移动评论以回答

您的问题是您正在使用非虚拟函数(方法隐藏)而不是切片。

每当在子类中定义一个函数时,它将&#34;隐藏&#34;在父类中实现相同的方法。

您要做的是将方法声明为虚拟:

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将指向正确的方法调用)。切片会给你带来可怕的堆栈和堆损坏错误,并使值看起来很奇怪......&#34;未定义的行为&#34;虽然如此,但它仍然会在课堂上调用正确的虚函数!

答案 1 :(得分:0)

这不是一个切片问题。我认为您只是想Use virtual而不是{{1}}。