vector.push_back(B)和vector.push_back(new A((* B))),为什么不一样呢?

时间:2013-06-12 14:20:55

标签: c++ oop inheritance

我有这两个类:

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;

的原因是什么?

4 个答案:

答案 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的字段。