多态
多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
静态多态:函数重载 和 运算符重载 属于 静态多态,复用函数名
动态多态:派生类 和 虚函数 实现运行时多态
静态多态和动态多态区别:
(1)静态多态的函数地址早绑定 – 编译阶段确定函数地址
(2)动态多态的函数地址晚绑定 – 运行阶段确定函数地址
下面通过案例进行讲解多态
#include<iostream>
using namespace std;
//多态
class Animal{
public:
virtual void speak(){ //加上virtual后,函数变为虚函数
cout << "动物在说话" << endl;
}
};
class Cat :: public Animal{
public:
void speak(){
cout << "小猫在说话" << endl;
}
}
18行:void doSpeak(Animal &animal){ //Animal &animal = cat 父类的引用在指向子类的对象
//静态多态
animal.speak(); //这里调用的是父类的speak()函数,也就是动物在说话,因为这里函数的地址是早绑定的,也就是一开始就绑定了父类中的speak()函数,在编译阶段就确定了函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定,解决方法,在speak()函数前加virtual,将函数更改为虚函数
//动态多态
animal.speak(); //这里就是猫在说话
}
void test01(){
Cat cat;
doSpeak(cat);
}
int main(){
test01();
system("pause") ;
return 0;
}
总结:
动态多态满足条件
1、有继承关系
2、子类要重写父类的虚函数(子类中重写函数时可以不用加virtual,但是父类中必须加)
动态多态使用
父类的指针或者引用,执行子类对象(也就是第18行的代码)
多态的底层原理:
#include<iostream>
using namespace std;
//多态
class Animal{
public:
void speak(){ //加上virtual后,函数变为虚函数
cout << "动物在说话" << endl;
}
};
class Cat :: public Animal{
public:
void speak(){
cout << "小猫在说话" << endl;
}
}
void doSpeak(Animal &animal){ //Animal &animal = cat 父类的引用在指向子类的对象
animal.speak();
animal.speak();
}
void test01(){
Cat cat;
doSpeak(cat);
}
void test02(){
cout << "sizeof Animal = " << sizeof(Animal) << endl; //现在Animal类中只有一个非静态的成员函数,他不属于类的对象,是分开存储的,那Animal相当于是一个空类,那么他的大小就是sizeof(Animal) = 1;
//如果加上virtual关键字,那么sizeof(Animal) = 4,这4个字节是一个指针,如图1详解
}
int main(){
test01();
test02();
system("pause") ;
return 0;
}
图1
子类将父类拷贝一份之后speak函数的入口地址是Animal类中的speak函数地址,&Cat :: speak 这个代码将speak函数的入口地址变为Cat对象的speak函数地址,然后会将原来子类中&Animal::speak函数的地址覆盖掉,如下图所示
这里就相当于子类将父类的虚函数给替换掉了,但是父类中的虚函数并没有发生改变
当父类的指针或者引用指向子类对象的时候,发生多态
Animal *animal = cat ;
animal.speak();
由于指向的是一个cat对象,那么他会去cat的虚函数表中去找speak函数,这是在运行阶段
多态案例一-计算器类
案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类
多态的优点:
(1)代码组织结构清晰
(2)可读性强
(3)利于前期和后期的扩展以及维护
include<iostream>
using namespace std;
//分别利用普通写法和多态技术实现计算器
//普通写法
class Calculator{
public:
int getResu1t(string oper){
if (oper == "+"){
return m_Num1 + m_Num2 ;
}else if (oper == "-"){
return m_Num1 - m_Num2;
}else if (oper == "*"){
return m_Num1 * m_Num2;
}
//如果想扩展新的功能,需要修改源码
int m_Num1 ;//操作数1
int m_Num2;//操作数2
};
void test01(){
//创建计算器对象
Caiculator c;
c.m_Num1 = 10;
c.m_Num2 = 10;
cout << c.m_Num1 << " + " << c.m_Num2〈<<" = " << c.getResult("+") << end1;//20
cout << c.m_Num1 << " - " << c.m_Num2〈<<" = " << c.getResult("-") << end1;//0
cout << c.m_Num1 << " * " << c.m_Num2〈<<" = " << c.getResult("*") << end1;//100
}
//利用多态实现计算器
//实现计算器抽象类
class AbstractCalculator
public:
virtual int getResult(){
return 0;
}
int m_Num1;
int m_Num2;
};
//加法计算器类
class AddCalculator : public AbstractCalculator{
public:
virtual int getResult(){
return m_Num1 + m_Num2;
}
}
//减法计算器类
class SubCalculator : public AbstractCalculator{
public:
virtual int getResult(){
return m_Num1 - m_Num2;
}
}
void test02(){
//多态使用条件
//父类指针或者引用指向子类对象
AbstractCalculator * abc = new AddCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 <<"+"<< abc->m_Num2<< " = " << abc->getResult() << endl;
//用完记得销毁
delete abc;
abc = new SubCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 <<"-"<< abc->m_Num2<< " = " << abc->getResult() << endl;
delete abc;
}
int main(){
test01();
test02();
system("pause");
return 0;
}
多态带来的好处:
1、组织结构清晰
2、可读性强
3、对于前期和后期扩展以及维护性高
案例三:
案例描述:
电脑主要组成部件为CPU(用于计算),显卡(用于显示),内存条(用于存储)
将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
#include <iostream>
#include <string>
using namespace std;
class CPU{
public:
virtual void run_CPU() = 0;
};
class Screem{
public:
virtual void run_screem() = 0;
};
class RAM{
public:
virtual void run_ram() = 0;
};
class Computer{
public:
Computer(CPU *cpu,Screem *screem,RAM *ram){
m_CPU = cpu;
m_screem = screem;
m_RAM = ram;
}
~Computer(){
if(m_CPU == NULL){
delete m_CPU;
m_CPU = NULL;
}
if(m_screem == NULL){
delete m_screem;
m_screem = NULL;
}
if(m_RAM == NULL){
delete m_RAM;
m_RAM = NULL;
}
}
void dowork(){
m_CPU->run_CPU();
m_screem->run_screem();
m_RAM->run_ram();
}
private:
CPU *m_CPU;
Screem *m_screem;
RAM *m_RAM;
};
ostream &operator <<(ostream &cout,string &string){
cout << string.c_str()<<endl;
return cout;
}
class Inter_CPU:public CPU{
public:
virtual void run_CPU(){
cout << " Inter_CPU is running!"<<endl;
}
};
class Inter_Screem:public Screem{
public:
virtual void run_screem(){
cout <<" Inter_SCREEM is running!"<<endl;
}
};
class Inter_RAM:public RAM{
public:
virtual void run_ram(){
cout << " Inter_RAM is running!"<<endl;
}
};
void test01(){
Inter_CPU inter_cpu;
Inter_Screem inter_screem;
Inter_RAM inter_ram;
CPU *F_CPU = &inter_cpu;
Screem *F_SCREEM = &inter_screem;
RAM *F_RAM = &inter_ram;
Computer(F_CPU,F_SCREEM,F_RAM).dowork();
}
int main(){
test01();
system("pause");
return 0;
}