【问题标题】:vector.push_back(B) and vector.push_back(new A((*B))), why not act as the same? [duplicate]vector.push_back(B) 和vector.push_back(new A((*B))),为什么不一样呢? [复制]
【发布时间】:2013-06-08 17:04:00
【问题描述】:

我有这两个类:

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() 只是提示一个消息框。如果我使用“方式 1”,它没有问题,但如果我使用“方式 2”,它会提示没有文本的消息,这意味着 B 类的所有成员都是空的,就像他们从来没有被填充过一样.我通过使用std::shared_ptr 解决了这个问题,但是有没有其他方法可以不使用智能指针,因为我必须在一个大项目中实现这种方法,并且会有很多变化和失败。顺便问一下,“Way 2”的原因是什么?

【问题讨论】:

标签: c++ oop inheritance


【解决方案1】:
List_A.push_back(new A((*B_Instance))); // Way 2

这条线没有做你认为的那样。

您正在通过调用 C++ 生成的默认复制构造函数在堆上创建类“A”的新实例。该复制构造函数使用 B 的实例(将其视为 A 的实例)并进行逐个字段的复制,在这种情况下,它什么也不做。

您实际上是在创建 A 的一个空实例并将其推送到列表中。

正如许多人所提到的,这方面的正式术语称为object slicing

【讨论】:

    【解决方案2】:

    这意味着 B 类的所有成员都是空的,就像他们从来没有被任何东西填充过一样

    没有。这并不意味着它们是空的。要为空,它们首先必须在那里。

    List_A[1]-&gt;TellMyName(); 执行动态调度并最终调用A::TellMyName,因为class A 是对象的实际类型。 B 类的成员甚至都不存在。

    你遇到了切片问题。

    【讨论】:

      【解决方案3】:
      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
      

      说了这么多,顺便说一句,我强烈建议您考虑重构代码以使用智能指针。

      【讨论】:

        【解决方案4】:

        你应该打电话

        List_A.push_back(new B((*B_Instance)));
        

        由于B继承自A,它也可以添加到列表中,但由于B的复制构造函数也会复制B中的所有字段,所以它会起作用。

        调用A 的复制构造函数不会复制B 中的字段,因为A 并不“知道”B 的字段。

        【讨论】:

          猜你喜欢
          • 2021-10-06
          • 1970-01-01
          • 2019-10-27
          • 2013-06-25
          • 2019-01-12
          • 1970-01-01
          • 2014-03-29
          • 2011-08-10
          • 2019-01-19
          相关资源
          最近更新 更多