原创 是否只有通过基类指针或引用间接指向派生类子类型时,多态性才会起作用?(转载)

2011-4-20 10:12 2541 3 3 分类: MCU/ 嵌入式

只有通过基类指针或引用间接指向派生类子类型时,多态性才会起作用。使用基类对象并不会保留派生类的类型身份,不再具备多态性。

 

深入讨论:

这个问题和答案有一点模糊,让我们通过一个示例来明确这个问题。

#include <iostream>

class Base {

public:

         virtual void f() {

                   std::cout<< “Calling Base::f()…\n”;

         };

};

 

class Derived: public Base {

public:

         virtual void f() {

                   std::cout<< “Calling Derived::f()…\n”;

         };

};

类Base和Derived,Derived从Base继承而来,子类Derived覆盖(Override)了基类Base中定义的虚函数f()。如果通过基类对象指针或引用来调用虚函数f(),那么会调用类对象的动态类型中所定义的函数,多态性发挥了作用。所以,如果执行如下代码:

Base* pb = new Base();

Base* pd = new Derived();

 

pb->f();

pd->f();

 

Base& rb = *pb;

Base& rd = *pd;

 

rb.f();

rd.f();

会得到如下结果。

Calling Base::f()...

Calling Derived::f()...

Calling Base::f()...

Calling Derived::f()...

如果通过基类对象来调用虚函数f(),基类对象并不会保留派生类的类型身份,不再具备多态性。所以,如果执行如下代码:

Derived d;

Base b = d; // d被“切割”成一个Base对象

d.f();

会得到如下结果。

Calling Base::f()...

尽管用d初始化b是合法的,但是b不再是一个Derived对象。在初始化b之前,d的Derived部分被切除,成为了一个Base对象。所以,最后调用了方法Base::f()。这也是C++被人广为诟病的特性之一,作为一种面向对象编程语言,我们必须使用指针以引用而不是对象来支持面向对象程序设计。

可能有一些善于思考的读者会想到一种情况:如果基类对象通过解引用操作符*获得,调用虚函数是否具备多态性?例如,执行如下代码会得到什么结果:

Base* pb = new Base();

Base* pd = new Derived();

Base b = *pd;

b.f();

(*pd).f();

执行结果如下:

Calling Base::f()...

Calling Derived::f()...

为什么(*pd).f()会调用Derived::f()?因为通过解引用操作符*获得不是一个基类Base对象,而是子类Derived对象。

 

参考资料:

《C++ Primer》第四版章节17.5导言部分。

《Inside C++ Object Model》章节1.3。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
3
关闭 站长推荐上一条 /3 下一条