简体   繁体   中英

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

I'm learning C++ now and I read a lot of materials about using superclass's pointer to point to a subclass' object, especially in the case of (pure) virtual classes. Since I don't have a lot of experience, could anyone help me to understand why we need to do that? Thanks a lot!

You don't need to. You can use a pointer to the derived type if that's what you really want.

The Liskov substitution principle says that we should always be able to use a derived type wherever the base type is expected. The idea is that a derived type should be no more restrictive than its base class. That way, the derived really is-a base type, and can be used wherever the base type would be used. The base type defines the interface and the derived type should meet that same interface. The derived type can augment the interface, if it likes.

The type of pointer that your function should take depends on exactly what you want to be able to accept. If you have a hierarchy with two Widget s, Button and List , for example, then if your function is happy to take any kind of Widget , it should take a Widget* . If the function specifically requires a Button , however, it should take a Button* . The reason for this is that the function probably requires some functionality that only the Button can provide.

When a member function is called through a pointer and the compiler sees that that function is virtual , the compiler ensures that the dynamic type of the object is used to determine which function to call. That is, imagine you have a Widget* parameter but actually pass a pointer to a Button object. The static type of the object is Widget (if the compiler were to only look at the parameter type), but its dynamic type is Button . If you call widget->draw() , where draw is a virtual function, it will see that the dynamic type is Button and ensure that Button::draw is called.

However, I don't recommend using raw pointers in general, so prefer references ( Widget& ) or smart pointers if you can.

Here's an example:

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

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

Consider that you have client code that wants to call do_stuff.

First implementation (this is how not to do it):

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

This function works. If you decide (four months from now) to add to your code base:

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

You may want to call void client_do_stuff for an instance of specialization2 . You could duplicate client_do_stuff with a specialization2 reference, but that is code duplication and unnecessary.

A better solution would be to change client_do_stuff to take a reference to the base class, and use the same implementation with both specializations.

Second implementation :

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

client code:

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

This implementation of client_do_stuff is implemented in terms of the public interface of the base class, instead of a specialization. This makes the function "future-proof" (the principle is sometimes called "program to an interface, not an implementation").

The idea is as follows: An object has the following interface (the pure virtual class). I will hand a concrete object to your code, which adheres to this interface, but the internal details of said object I will keep to myself (encapsulation). Thus your code can make no assumptions on the precise size etc. of the object. Therefore when compiling your code, you have to use pointers or references when manipulating the object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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