问题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();
|
会得到如下结果。
尽管用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。
分享到:
相关推荐
C++中的多态性是面向对象编程的重要概念,它允许使用基类指针或引用来调用派生类的方法。这种灵活性使得程序可以根据实际对象的类型来执行适当的操作。 代码中,我们定义了一个基类 Animal,其中包含了一个虚函数 ...
多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界...
- 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界...
- 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。 简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。 多态性分为编译时的多态性和运行时的多态性。 总共90多道题目,包含面向...
接下来有函数调用pThread->InitInstance(),根据多态性,会调用CXXXApp类中的InitInstance()函数。该函数很重要,在对该函数的调用中就会完成:设计窗口类->注册窗口类->生成窗口->显示窗口->更新窗口。 接下来,该...
10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166 10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 ...
1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入bbbwlirbbb,输出...
10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166 10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 ...
多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 5、String是最基本的数据类型吗? 基本数据类型包括byte、int、char、long、...
多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 2、String是最基本的数据类型吗? 基本数据类型包括byte、int、char、long、float、...
通过实现继承与多态性,还可以大大提高程序的可重用性,使得软件的开发和维护都更为方便。 面向对象方法所强调的基本原则,就是直接面对客观存在的事物来进行软件开发,将人们在日常生活中习惯的思维方式和表达方式...
13.4 继承是否可以实现多态性 13.5 在编译时的静态联编 13.6 在运行时的静态联编 13.7 在运行时的动态联编 13.8 在编译时的动态联编 13.9 调用虚函数 13.9.1 在虚函数中调用成员函数 13.9.2 3种调用虚函数的方式比较...
13.4 继承是否可以实现多态性 13.5 在编译时的静态联编 13.6 在运行时的静态联编 13.7 在运行时的动态联编 13.8 在编译时的动态联编 13.9 调用虚函数 13.9.1 在虚函数中调用成员函数 13.9.2 3种调用虚函数的...
方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。 运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事: 1). 方法重写...
一套非常好的C++教学电子教案,本人曾经在一所高职院校兼职代课,用的就是这套ppt。适合初学者学习使用。 =========================== 1.绪论; ...13.多态性和虚函数; 14.IO流; 15.异常处理;
1.1.3多态性 1.1.4操作概念:OOP程序像什么 1.2为什么C++会成功 1.2.1较好的C 1.2.2采用渐进的学习方式 1.2.3运行效率 1.2.4系统更容易表达和理解 1.2.5“库”使你事半功倍 1.2.6错误处理 1.2.7大程序设计 1.3方法...
构造与析构函数,函数的重载,类的继承,函数覆盖,基类与派生类的构造函数、析构函数先后调用顺序,如何在派生类构造函数中向基类的构造函数传递参数,this成员变量,类型转换的内幕,虚拟函数与奇妙多态性。...
大学C++课本,谭浩强版,电子教案。 第1篇 基 本 知 识 第1章 C++的初步知识 第2章 数据类型与表达式 第2篇 面向过程的程序设计 ... 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具