繁体   English   中英

为什么我们需要超类的指针指向子类的对象?

[英]Why do we need a pointer of superclass to point to a object of a subclass?

我现在正在学习C ++,并且阅读了许多有关使用超类的指针指向子类的对象的资料,尤其是在(纯)虚拟类的情况下。 由于我没有太多经验,所以谁能帮助我了解我们为什么需要这样做? 非常感谢!

你并不需要 如果您确实需要,可以使用指向派生类型的指针。

Liskov替换原则说,无论何时需要基本类型,我们都应该始终能够使用派生类型。 这个想法是,派生类型的限制不应超过其基类。 这样,派生的实际上是-基本类型,并且可以在将要使用基本类型的任何地方使用。 基本类型定义接口,派生类型应满足该相同接口。 如果喜欢,派生类型可以扩展接口。

函数应该采用的指针类型取决于您希望能够接受的指针。 例如,如果您有一个包含两个Widget的层次结构,即ButtonList ,则如果您的函数乐于采用任何一种Widget ,则应采用Widget* 但是,如果该函数特别需要一个Button ,则应使用Button* 这样做的原因是该功能可能需要某些只有Button才能提供的功能。

当通过指针调用成员函数并且编译器看到该函数是virtual ,编译器将确保使用对象的动态类型来确定要调用的函数。 也就是说,假设您有一个Widget*参数,但实际上将指针传递给Button对象。 对象的静态类型是Widget (如果编译器仅查看参数类型),但其动态类型是Button 如果调用widget->draw() ,其中drawvirtual函数,它将看到动态类型为Button并确保调用了Button::draw

但是,我一般不建议使用原始指针,因此,如果可以的话,最好使用引用( Widget& )或智能指针。

这是一个例子:

struct base { virtual void do_stuff(); = 0 };

struct specialization1: base {
    void do_stuff() override { std::cout << "doing concrete stuff"; }
};

考虑您具有要调用do_stuff的客户端代码。

第一次执行 (这是执行的操作):

void client_do_stuff( specialization1& s ) { s.do_stuff(); }

此功能有效。 如果您决定(从现在开始四个月)添加到您的代码库中:

struct specialization2: base {
    void do_stuff() override { std::cout << "doing other concrete stuff"; }
};

您可能需要调用void client_do_stuff的实例specialization2 您可以使用specialization2参考来复制client_do_stuff ,但这是代码重复并且不必要。

更好的解决方案是将client_do_stuff更改为对基类的引用,并对这两个专业化使用相同的实现。

第二实施

void client_do_stuff( base& b ) { b.do_stuff(); }

客户代码:

specialization1 s1;
specialization2 s2;
client_do_stuff(s1); // works
client_do_stuff(s2); // works

client_do_stuff的此实现是根据基类的公共接口而不是专门化实现的。 这使功能“面向未来”(该原理有时称为“接口编程,而不是实现”)。

这个想法如下:一个对象具有以下接口(纯虚拟类)。 我将把一个具体的对象传递给您的代码,该代码遵循此接口,但是我将自己保密(封装)该对象的内部细节。 因此,您的代码无法假设对象的精确大小等。 因此,在编译代码时,在处理对象时必须使用指针或引用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM