我相信我有一个切片问题,我不知道如何解决它。我已将实际程序中的问题总结为下面的示例。
#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?中列出的一些解决方案,但我不相信我正确应用它们。
答案 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}}。