0

我有这两个类:

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”的原因是什么?

4

4 回答 4

6
List_A.push_back(new A((*B_Instance))); // Way 2

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

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

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

正如许多人所提到的,这方面的正式术语称为对象切片

于 2013-06-12T14:24:40.970 回答
2

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

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

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

您遇到了切片问题。

于 2013-06-12T14:26:25.987 回答
2
std::vector<A*> List_A;
// ...
List_A.push_back(new A((*B_Instance))); // Way 2

您正在遭受某种形式的Object Slicing之苦。

当您使用派生类型的值实例化(或分配)基类并丢失(或“切掉”)派生类独有的所有内容时,就会发生对象切片。

上面,您正在实例化 a new A,而不是 a new B。但由于B派生自A,您可以简单地实例化 anew B并将返回的指针转换为 a A*

List_A.push_back(new B(*B_Instance)); // Way 2

综上所述,顺便说一句,我强烈建议您考虑重构代码以使用智能指针。

于 2013-06-12T14:26:46.083 回答
2

你应该打电话

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

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

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

于 2013-06-12T14:27:48.467 回答