声明基类类型的指针,但随后通过指向子类来实例化它.这是良好的编程实践吗?

Declare a pointer of type base class, but then instantiate it by pointing to a child class. Is this good programming practice?

本文关键字:实例化 编程 指针 类型 基类 声明 子类      更新时间:2023-10-16

我正在尝试围绕多态性和指针来思考,并正在关注一些精彩的视频来解释它(如果您真的关心,请超链接)

他宣称class Aclass B继承自A。

但是为了实例化 B 的对象,他这样做是这样的:

A* b = new B;

它工作正常(他在创建更复杂的类时继续使用该方法,一个包含子类 Square、Circle 等的基本类型 Shape 的矢量数组,即

std::vector<Shape*> shapes;
shapes.push_back(new Circle.........
shapes.push_back(new Rectangle.......

这是可能的,但是声明指向基类对象的指针,然后通过指向其子类来实例化它是否完全可以(甚至推荐)?

我想我刚刚回答了我自己的问题,好处来自于能够通过父类引用它们来管理不同对象的集合?这是对的吗?

谢谢!

但是声明

指向基类对象的指针,然后通过指向其子类来实例化它是否完全可以(甚至推荐)?

当您使用

A* ptr = new B();

而不是

B* ptr = new B();

您只丢失了少量信息。不能使用在B中定义但不能在A中定义的任何成员函数。 请注意,使用virtualA声明但在B中实现的成员函数是完全可以的。

如果在您的用例中可以承受少量损失,那么使用A* ptr =就没有害处了。如果您希望能够保留指针的B性,以便可以使用它来访问特定于B的成员,则必须使用B* ptr =


有一个关于使用指针/引用类型的指导原则:

  1. 定义函数接口时,请使用在类层次结构中尽可能高的指针/引用类型来实现函数。

    鉴于

    struct Shape { ... };
    struct Circle : Shape { ... };
    

    不要在函数的接口中使用Circle,如果你在函数中需要的所有内容都可以从Shape获得。

    当你添加Shape的下一个子类时,

    struct Rectangle : Shape { ... };
    

    该函数也可以与Rectangle一起使用,而无需进行任何更改。

  2. 定义指针/引用时,请使用保留尽可能多的信息的类型。

    如果有函数

    Circle* someFunction();
    

    然后,使用

    Circle* circlePtr = someFunction();
    

    而不是

    Shape* shapePtr = someFunction();
    

    您可以在任何需要Shape*的地方使用circlePtr,但您将无法在需要Circle*的任何地方使用shapePtr

您部分回答了您的问题,但也可能有其他原因。

多态性是这样你就可以保持一些抽象的东西。例如,想象一下这样的代码:

Person *actor;
if (occupation == 'nerd') {
actor = new NerdPerson();
}
else if (occupation == 'mortician') {
actor = new MorticianPerson();
}
...
actor->printOccupation();

显然,这是一个编造的理由。所以它可能是关于某些东西的集合,但这只是一个原因。