您的位置:首页 > 其它

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

2016-06-11 21:20 302 查看

来自:http://www.ithao123.cn/content-971985.html


问题2:是否只有通过基类指针或引用间接指向派生类子类型时,多态性才会起作用?

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

 
深入讨论:
这个问题和答案有一点模糊,让我们通过一个示例来明确这个问题。
#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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: