C++学习22 多态的概念及前提条件
在《C++基类和派生类的赋值》一节中讲到,基类的指针也可以指向派生类对象。请看下面的例子:
#include <iostream>
using namespace std;
class People{
protected:
char *name;
public:
People(char *name):name(name){}
void display(){ cout<<"People: "<<name<<endl;}
};
class Student: public People{
public:
Student(char *name):People(name){}
void display(){ cout<<"Student: "<<name<<endl;}
};
int main(){
People *p = new People("Xiao Ming");
p->display();
p = new Student("Li Lei");
p->display();
return ;
}
运行结果:
People: Xiao Ming
People: Li Lei
我们通常认为,如果指针指向了派生类对象,那么就应该使用派生类的成员变量和成员函数,这符合人们的思维习惯。
但是本例的运行结果却告诉我们:当基类指针 p 指向派生类 Student 的对象时,虽然使用了 Student 的成员变量,但是却没有使用它的成员函数,造成输出结果不伦不类,不符合我们的预期。
如果希望通过 p 指针访问 Student 类的成员函数,可以将该成员函数声明为虚函数,请看下面的代码:
#include <iostream>
using namespace std;
class People{
protected:
char *name;
public:
People(char *name):name(name){}
//加virtual关键字声明为虚函数
virtual void display(){ cout<<"People: "<<name<<endl;}
};
class Student: public People{
public:
Student(char *name):People(name){}
//加virtual关键字声明为虚函数
virtual void display(){ cout<<"Student: "<<name<<endl;}
};
int main(){
People *p = new People("Xiao Ming");
p->display();
p = new Student("Li Lei");
p->display();
return ;
}
运行结果:
People: Xiao Ming
Student: Li Lei
与上面的代码相比,这段代码仅仅是在 display() 函数声明前加了一个 virtual 关键字,将成员函数声明为了虚函数(Virtual Function)。这样,就可以通过 p 指针调用 Student 类的成员函数了,运行结果也证明了这一点。
借助虚函数,基类指针既可以使用基类的成员函数,也可以使用派生类的成员函数,它有多种形态,或多种表现方式,这就是多态(Polymorphism)。
上面的代码中,同样是p->display();
这条语句,当 p 指向不同的对象时,它执行的操作是不一样的。同一条语句可以执行不同的操作,看起来有不同表现方式,这就是多态
多态是面向对象的主要特征之一。在C++中,虚函数的唯一用处就是构成多态。
C++提供多态的目的是:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。如果没有多态,我们只能访问成员变量。
构成多态的条件
多态存在的三个条件:
- 必须存在继承关系;
- 继承关系中必须有同名的虚函数,并且它们是覆盖关系(重载不行)。
- 存在基类的指针,通过该指针调用虚函数。
注意:派生类中的虚函数必须覆盖(不是重载)基类中的虚函数,才能通过基类指针访问。请看下面的代码:
#include <iostream>
using namespace std;
class Base{
public:
void a(){ cout<<"Base::a()"<<endl; }
virtual void b(){ cout<<"Base::b()"<<endl; }
virtual void c(){ cout<<"Base::c()"<<endl; }
};
class Derived: public Base{
public:
//覆盖基类普通成员函数,不构成多态
void a(){ cout<<"Derived::a()"<<endl; }
//覆盖基类虚函数,构成多态
virtual void b(){ cout<<"Derived::b()"<<endl; }
//重载基类虚函数,不构成多态
virtual void c(int n){ cout<<"Derived::c()"<<endl; }
//派生类新增函数
int d(){ cout<<"Derived::d()"<<endl; }
};
int main(){
Base *p = new Derived;
p -> a();
p -> b();
p -> c(); //Compile Error
p -> d(); //Compile Error
return ;
}
C++学习22 多态的概念及前提条件的更多相关文章
- 4.1 C++多态的概念及前提条件
参考:http://www.weixueyuan.net/view/6370.html 总结: 而多态的功能则是将函数名动态绑定到函数入口地址,这样的动态绑定过程称为运行期绑定. 而在运行期绑定的函数 ...
- 程序基石系列之C++多态的前提条件
准备知识 C++中多态(polymorphism)有下面三个前提条件: 必须存在一个继承体系结构. 继承体系结构中的一些类必须具有同名的virtual成员函数(virtualkeyword) 至少有一 ...
- JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例
JAVA之旅(八)--多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例 学习是不能停止的 一.多态 我们今天又要学习一个新的概念了,就是多态,它是面向对象的第 ...
- C++学习笔记-多态
多态作为面向对象的重要概念,在如何一门面向对象编程语言中都有着举足轻重的作用,学习多态,有助于更好地理多态的行为 多态性(Polymorphism)是指一个名字,多种语义:或界面相同,多种实现. 重载 ...
- [转帖]java基础学习总结——多态(动态绑定)
https://www.cnblogs.com/xdp-gacl/p/3644035.html 多态的概念 java基础学习总结——多态(动态绑定) 一.面向对象最核心的机制——动态绑定,也叫多态
- Java学习之 多态 Polymorphism
转自:http://www.cnblogs.com/mengdd/archive/2012/12/25/2832288.html 多态的概念 多态==晚绑定. 不要把函数重载理解为多态. 因为多态是一 ...
- Java学习之多态
多态的概念 多态==晚绑定. 不要把函数重载理解为多态. 因为多态是一种运行期的行为,不是编译期的行为. 多态:父类型的引用可以指向子类型的对象. 比如 Parent p = new Child(); ...
- Optaplanner逐步学习(0) : 基本概念 - Optaplanner,规划问题, 约束,方案
之前的文章中,分别从APS,排产到规划引擎叙述了一些理论基础:并介绍了一些Optaplanner大概的情况:并一步步将Optaplanner的示例运行起来,将示例源码导进Eclipse分析了一下它的H ...
- C++中多态的概念和意义
1,函数重写回顾: 1,父类中被重写的函数依然会继承给子类: 2,子类中重写的函数将覆盖父类中的函数: 1,重写父类当中提供的函数是因为父类当中提供的这个函数版本不能满足我们的需求,因此我们要重写: ...
随机推荐
- TaffyDB:开源JavaScript数据库
你是否曾经注意到javascript的对象有点像数据库中的记录,你把很多javascript对象包装到一起时就像是你在处理一个数据库中的表,TaffyDB是一个Javascript库,它提供了强大的数 ...
- Mysql 排序优化与索引使用(转)
为了优化SQL语句的排序性能,最好的情况是避免排序,合理利用索引是一个不错的方法.因为索引本身也是有序的,如果在需要排序的字段上面建立了合适的索引,那么就可以跳过排序的过程,提高SQL的查询速度.下面 ...
- web前端基础知识及快速入门指南
web前端基础知识及快速入门指南 做前端开发有几个月了,虽然说是几个月,但是中间断断续续的上课.考试以及其它杂七杂八的事情,到现在居然一直感觉自己虽然很多前端的知识很眼熟,却也感觉自己貌似也知识在门口 ...
- div的打开与关闭js
<script type="text/javascript"> var BoxHeight=$('.t_c').css("height"); //$ ...
- JavaScript中的继承模式总结
一.总结: //js中的几种继承 //原型链的问题,包含引用类型的原型属性会被实例共享,子类型无法给超类型传递参数 function SuperType() { this.colors = [&quo ...
- apply()和call()的区别
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值. apply()接收两个参数:一个参数是在其中运行的作用域,另一个是参数数组(可以是Array实例,也可以是arg ...
- 安卓ROOT后禁用/隐藏导航栏/虚拟按键
安卓ROOT后禁用/隐藏导航栏/虚拟按键 提醒:提前装好EASY TOUCH 等类似工具. 用ROOT EXPLORER 或 ROOT BROWSER system\bulid.prop 最后加一行: ...
- mysql中int转varchar
这里要注意,cast(XX as varcahr(10))在mysql中不好使,要cast(XX as char(10))这样才好使
- protobuffer序列化
一. 描述对象的proto文件 第一行package:对象经过protobuffer编译后形成java文件,这个文件放在按照package新建的文件夹内 java_package:java类的包名 j ...
- Topology的构建
public class BlackListBolt extends BaseRichBolt{ private static Logger logger = Logger.getLogger(Bla ...