c++之——多态性
先看一个例子:
#include<iostream>
using namespace std; class Liberation {
public:
Liberation(int a):capability(a)
{
cout << "Liberation 构造函数\n";
}
int combat()
{
return capability;
}
private:
int capability;
};
class Liberation_adv :public Liberation
{
public:
Liberation_adv(int a) :Liberation(a), capability(a)
{
cout << "Liberation 构造函数\n";
}
int combat()
{
return capability;
}
private:
int capability;
}; class Enemy {
public:
Enemy(int a):capability(a)
{
cout << "Enemy 构造函数\n";
}
int combat()
{
return capability;
}
private:
int capability;
};
int main()
{
Liberation L1();
Enemy E1();
Liberation_adv L2();
if (L1.combat() < E1.combat())
{
cout << "一代军队战败\n";
}
else
{
cout << "一代军队胜利\n";
}
if (L2.combat() < E1.combat())
{
cout << "二代军队战败\n";
}
else
{
cout << "二代军队胜利\n";
} return ;
}
然后我们引进多态,看看代码升级的威力;
#include<iostream>
using namespace std; class Liberation {
public:
Liberation(int a):capability(a)
{
cout << "Liberation 构造函数\n";
}
virtual int combat()
{
return capability;
}
private:
int capability;
};
class Liberation_adv :public Liberation
{
public:
Liberation_adv(int a) :Liberation(a), capability(a)
{
cout << "Liberation 构造函数\n";
}
int combat() override //派生类重写的函数不用加virtual也是virtual的,建议加上,方便后续继承这个类的文档阅读,c++11增加关键字
//override告诉编译器和读者,这是个被重写的函数
{
return capability;
}
private:
int capability;
}; class Enemy {
public:
Enemy(int a):capability(a)
{
cout << "Enemy 构造函数\n";
}
int combat()
{
return capability;
}
private:
int capability;
}; void play(Liberation &L, Enemy &E)
{
if (L.combat() < E.combat())
cout << "敌军胜利\n";
else {
cout << "我军胜利\n";
}
}
int main()
{
Liberation L1();
Enemy E1();
Liberation_adv L2();
play(L1, E1);
play(L2, E1);
return ;
}
用多态的好处:调用一个函数,简化代码结构,关键在于可维护性好。如果现在我又派生了一个类L3,只用调用函数的接口,就可以仅仅增加一个类定义的情况下,完成项目的维护。
实现多态三要素:
1、要有public继承;
2、要有虚函数重写;
3、要有基类的指针或者引用绑定到派生类。
满足上诉要求,可以实现动态联编(运行时类型才可知),否则是静态联编(编译时类型就已知)。
C++中的多态(polymorphism)是指由继承而产生的相关的不同的类, 其对象对
同一消息会作出不同的响应。
多态性是面向对象程序设计的一个重要特征, 能增加程序的灵活性。 可以减
轻系统升级, 维护, 调试的工作量和复杂度。
多态是一种不同层次分类下的重要联系, 是一种跨层操作。
多态实现的前提
赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。
赋值兼容是一种默认行为, 不需要任何的显式的转化步骤, 只能发生在 public
继承(其他private和protected继承,多态无意义,因为不能在类外访问属性或方法了)方式中, 是多态实现的前提条件。
赋值兼容规则中所指的替代包括以下的情况:
A、 子类对象可以直接赋值给父类对象
B、 子类对象可以直接初始化父类对象
C、 父类引用可以直接引用子类对象
D、 父类指针可以直接指向子类对象
当使用父类指针(引用) 指向子对象时, 子类对象退化为父类对象, 只能访问父类中定义的成员
父类也可以通过强转的方式转化为子类, 但存在访问越界的风险。
子类中可以重定义父类中已经存在的成员函数, 即函数重写。
当函数重写遇到赋值兼容时, 编译器只能根据指针的类型判断所指向的对
象, 根据赋值兼容原则, 编译器认为父类指针指向的是父类对象, 只能调用父类
中定义的同名函数。
面向对象编程中, 通常需要根据实际的对象类型判断如何调用重写函数。 当
父类指针指向父类对象, 则调用父类定义的函数; 当父类指针指向的是子类对象
时, 需要调用子类定义的函数; 当父类引用对父类对象进行引用时, 调用父类对
象定义的函数; 当父类引用对子类对象进行引用时, 调用子类定义的函数。
C++通过 virtual 关键字对多态进行支持, 被 virtual 声明的函数被重写后具有多态属性。
虚函数的声明语法如下:
virtual 函数声明;
虚函数的使用规则如下:
A、 在父类中用 virtual 声明成员函数为虚函数。 类外实现虚函数时, 不能再加 virtual。
B、 在派生类中重定义父类中已经存在的成员函数称为函数覆写, 要求函数名,
返值类型, 函数参数个数及类型全部匹配, 并根据派生类的需要重新定义函数体。
C、 当一个成员函数被声明为虚函数后, 其派生类中完全相同的函数也为虚函
数, 派生类中的虚函数可以加 virtual 关键字, 也可以不加,建议都加上,为了代码扩展和阅读(如果不写virtual(虽然不写也是virtual的),
之后有一个类继承这个派生类,只看这个派生类的声明,不能一眼就看出这个派生类重写了该派生类的直接或者间接父类的函数)。
D、 定义一个父类对象指针, 使其指向其子类的对象, 通过父类指针调用虚函
数, 此时调用的是子类的同名函数,引用同理。
E、 构造函数不能为虚函数, 在构造函数执行完毕后虚函数表指针才能被正
确初始化。 析构函数可以为虚函数, 一般来说需要将析构函数声明为虚函数。 构造函数执行时, 虚函数表指
针未被正确初始化, 因此构造函数不可能发生多态; 析构函数函数执行时, 虚函
数表指针已经被销毁, 因此析构函数也不可能发生多态。 构造函数和析构函数中
只能调用当前类中定义的函数版本。
纯虚函数的声明语法如下:
virtual 函数声明 = 0;
纯虚函数的使用规则如下:
A、 含有纯虚函数的类, 称为抽象基类, 不可实例化, 即不能创建对象, 存在
的意义就是被继承, 提供类族的公共接口。
B、 纯虚函数只有声明, 没有实现。
C、 如果一个类中声明了纯虚函数, 而在派生类中没有对纯虚函数进行实现,
则该虚函数在派生类中仍然为纯虚函数, 派生类仍然为抽象基类。
虚函数的使用规则如下:
A、 只有类的成员函数才能声明为虚函数。 虚函数仅适用于有继承关系的类对
象, 所以普通函数不能声明为虚函数。
B、 静态成员函数不能是虚函数。 静态成员函数不受对象的捆绑, 只有类的信息。
C、 内联函数不能是虚函数。
D、 构造函数不能是虚函数。 构造时, 对象的创建尚未完成。 构造完成后, 才能算一个名符其实的对象。
E、 析构函数可以是虚函数且通常声明为虚函数
F、 含有虚函数的类, 析构函数也必须声明为虚函数。 在 delete 父类指针的时候, 会调用子类的析构函数。
多态的意义如下:
A、 在程序运行过程中展现出的动态特性
B、 函数重写必须多态实现, 否则没有意义
C、 多态是面向对象组件化程序设计的基础特性
D、 多态是一种跨层操作
静态联编是在程序的编译期间就能确定具体的函数调用, 如函数重载。
动态联编是在程序实际运行时才能确定具体的函数调用, 如virtual函数重写。
虚函数是为了实现动态多态, 是当程序运行到虚函数时才会从虚函数表里找
实际执行的虚函数; 而函数重载实现的是静态多态, 是在程序编译时就能找到
函数地址。
c++之——多态性的更多相关文章
- javaScript的原型继承与多态性
1.prototype 我们可以简单的把prototype看做是一个模版,新创建的自定义对象都是这个模版(prototype)的一个拷贝 (实际上不是拷贝而是链接,只不过这种链接是不可见,给人们的感觉 ...
- Java多态性——分派
一.基本概念 Java是一门面向对象的程序设计语言,因为Java具备面向对象的三个基本特征:封装.继承和多态.这三个特征并不是各自独立的,从一定角度上看,封装和继承几乎都是为多态而准备的.多态性主要体 ...
- 【C++】多态性(函数重载与虚函数)
多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...
- java多态性,父类引用指向子类对象
父类引用指向子类对象指的是: 例如父类Animal,子类Cat,Dog.其中Animal可以是类也可以是接口,Cat和Dog是继承或实现Animal的子类. Animal animal = new C ...
- 『c++』 模板(template)--- 参数化多态性
---恢复内容开始--- 题外话: 模板机制的设计和细节是由Bjarne Stroustrup在其1988年10月发表的名为“Parameterized Types for C++”一文中披露的. 引 ...
- Java对象的多态性(转型)
多态性在面向对象中主要有两种体现: <1>方法的重载与覆写 <2>对象的多态性 对象的多态性:向上转型:子类对象-->父类对象,向上转型会自动完成 向下转型:父类对象-- ...
- 【转】C++多态性
----转自http://blog.csdn.net/hackbuteer1/article/details/7475622 C++编程语言是一款应用广泛,支持多种程序设计的计算机编程语言.我们今天就 ...
- 浅谈C++多态性
本文转载至http://blog.csdn.net/hackbuteer1/article/details/7475622 总结: (1)区分概念: 重载----同一个类中,相同的函数名字,不同 ...
- Java基础之在窗口中绘图——利用多态性使用鼠标自由绘图(Sketcher 7 with a crosshair cursor)
控制台程序. 在Sketcher中创建形状时,并不知道应该以什么顺序创建不同类型的形状,这完全取决于使用Sketcher程序生成草图的人.因此需要绘制形状,对它们执行其他操作而不必知道图形是什么.当然 ...
- java多态性
多态分两种: (1) 编译时多态(设计时多态):方法重载. (2) 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态.(我们平时说得多的事运行时 ...
随机推荐
- python字符串格式化--dict传参
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python字符串格式化--dict传参 print "I'm %(name)s. I'm %(a ...
- SET GLOBAL FOREIGN_KEY_CHECKS取消外键约束
今天在工作中遇到的问题,在删除一个表时报错,发现有外键约束,所以不能删除,查了下发现需要取消外键约束. SET GLOBAL FOREIGN_KEY_CHECKS=0;全局取消外键约束 SET SES ...
- Linux 添加硬盘设备
fdisk命令用于管理磁盘分区,格式为:“fdisk [磁盘名称]”. 管理Linux系统中的硬盘设备最常用的方法就当属是用fdisk命令了,这条命令提供了添加.删除.转换分区等等功能于一身的“一站式 ...
- jQuery写缓存之:sessionStorage的运用,配合PHP将不同tab页的数据写入后台
JS(jQuery)写缓存之:sessionStorage的运用: 结果就是讲存储的DOM对象value传到后台PHP,进行foreach(){} 解析JSON成二维数组 示例页面:http://ww ...
- cxf之Caused by: java.lang.RuntimeException: Soap 1.1 endpoint already registered on address /rest
发布rest服务 但是spring-cxf-rest.xml中配置的却是 <jaxws:server address="/weather".................. ...
- js中的let和var
在ES6中,应该尽量使用const和let来声明变量,而尽量避免使用var. var的缺点是它的作用域比较混乱,使用let能够保证清晰的作用域. 下面看一个小例子. var x = 3; if(x== ...
- Java反射机制--笔记
1.认识Class类 任何一个类都是Class类的实例对象,这个实例对象有三种表示方式. /*java 反射机制*/ // 获取类的方法 UserDao userDao = new UserDao() ...
- Kafka server部署配置优化
Kafka配置优化其实都是修改server.properties文件中参数值 1.网络和io操作线程配置优化 # broker处理消息的最大线程数 num.network.threads ...
- 下载url地址的图片
// string url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=cNaaMfvhpb1vmcVRXRAdI ...
- OAF_OAF控件系列9 - Description Flexfiled描述性弹性域的实现(案例)
2014-06-17 Created By BaoXinjian