我有这两个类:
class A
{
public:
A();
virtual ~A();
virtual void TellMyName();
};
class B : public A
{
private:
std::string szName;
public:
B();
~B();
void TellMyName();
void SetName(std::string val){ szName = val; }
};
这是我的代码:
void main()
{
std::vector<A*> List_A;
B* B_Instance = new B();
B_Instance->SetName("B");
List_A.push_back(B_Instance); // Way 1
List_A.push_back(new A((*B_Instance))); // Way 2
List_A[0]->TellMyName();
List_A[1]->TellMyName();
}
TellMyName()
只会提示一个消息框。如果我使用&#34;方式1&#34;它没有问题,但如果我使用&#34; Way 2&#34;它会提示没有文字的消息,这意味着B类的所有成员都是空的,就像他们从未被任何东西填满一样。我使用std::shared_ptr
解决了这个问题,但是有没有其他方法可以不使用智能指针,因为我必须在一个大项目中实现这种方法,并且会有很多变化和失败。顺便说一下,&#34; Way 2&#34;
答案 0 :(得分:6)
List_A.push_back(new A((*B_Instance))); // Way 2
这条线没有按照你的想法行事。
您正在通过调用C ++生成的默认复制构造函数在堆上创建类“A”的新实例。该复制构造函数使用B的实例(将其视为A的实例),并进行逐字段复制,在这种情况下,不执行任何操作。
你实际上是在创建一个空的A实例并将其推送到列表中。
正如许多人所提到的,正式用语称为object slicing。
答案 1 :(得分:2)
这意味着B类的所有成员都是空的,就像他们从来没有被任何东西填充
没有。这并不意味着他们是空的。要空虚,他们必须首先在那里。
List_A[1]->TellMyName();
执行动态调度并最终调用A::TellMyName
,因为class A
是对象的实际类型。 <{1}}类的成员甚至不存在。
你遇到了切片问题。
答案 2 :(得分:2)
std::vector<A*> List_A;
// ...
List_A.push_back(new A((*B_Instance))); // Way 2
你正在遭遇Object Slicing的某种形式。
当您使用派生类型的值实例化(或分配)基类时,会发生对象切片,并丢失 - 或“切掉” - 派生类所特有的所有内容。
上面,您要实例化new A
,而不是new B
。但由于B
派生自A
,您只需实例化new B
并将返回的指针强制转换为A*
:
List_A.push_back(new B(*B_Instance)); // Way 2
所有这一切都说,但是,我强烈强烈建议您考虑重构代码以使用智能指针。
答案 3 :(得分:2)
你应该打电话
List_A.push_back(new B((*B_Instance)));
当B
继承自A
时,它也可以添加到列表中,但由于B
的复制构造函数也会复制B
中的所有字段,它将会工作
调用A
的复制构造函数不会复制B
中的字段,因为A
不会“知道”B
的字段。