多态的基本概念
多态是C++面向对象三大特性之一;
多态分为两大类:
1.静态多态:函数重载 和 运算符重载属于静态多态,复用函数名;
2.动态多态:派生类和弧函数实现运行时多态;
(我们讲的多态多为动态多态)
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 ——编译阶段确定函数地址;
动态多态的函数地址晚绑定 ——运行阶段确定函数地址;
class Animal {
public:
speak()就是虚函数
函数前面加上关键字virtual,变成虚函数,那么编译器在编译的时候就不能确定函数调用了;
virtual void speak() {
cout << "动物在说话" << endl;
}
};
class Cat :public Animal {
public:
重写 函数返回值类型 函数名 参数列表 完全相同
void speak() {
cout << "猫在说话" << endl;
}
};
class Dog :public Animal {
public:
//重写 函数返回值类型 函数名 参数列表 完全相同
void speak() {
cout << "狗在说话" << endl;
}
};
执行说话的函数
地址早绑定 在编译阶段确定函数地址
如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定;
void doSpeak(Animal &animal) {
Animal &animal = cat 父类的指针或者引用-执行子类对象
animal.speak();
}
int main() {
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
system("pause");
return 0;
}
总结:
动态多态满足条件
1.有继承关系
2.子类重写父类的虚函数
3.父类虚函数利用关键字:virtual声明,然后在子类中重写;
class Animal {
public:
speak()就是虚函数
函数前面加上关键字virtual,变成虚函数,那么编译器在编译的时候就不能确定函数调用了;
virtual void speak() {
cout << "动物在说话" << endl;
}
};
动态多态使用:父类的指针或者引用 执行子类对象
执行说话的函数
地址早绑定 在编译阶段确定函数地址
如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定;
void doSpeak(Animal &animal) {
Animal &animal = cat 父类的指针或者引用-执行子类对象
animal.speak();
}
Cat cat;
doSpeak(cat);
多态的原理剖析:
测试:
1.原空Animal类,sizeof大小为1;
2.当把speak()函数设置为virtual,设置为虚函数时,sizeof对象大小为4;
即对象变为vftr模型:
vfptr:(1).v:virtual:虚拟 (2).f:function;函数 (3).ptr:pointer;指针
所以,vfptr:虚函数(表)指针;——即指向虚函数表的指针;
vftable:虚函数表(表内记录虚函数地址)
测试:
案例1:计算机类
- 多态的优点:
- 1.代码组织结构清晰
- 2.可读性强;
- 3.利于前期和后期的扩展以及维护;
普通写法写计算器:
class Calculator {
public:
int getResult(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;
}
}
//如果想扩展新的功能,需求修改源码
//在真实的开发中提倡:开闭yuanze
//开闭原则:对扩展进行开发,对修改进行关闭
int m_Num1;
int m_Num2;
};
缺点:
如果想扩展新的功能,需求修改源码
- 在真实的开发中提倡:开闭原则
开闭原则:对扩展进行开放,对修改进行关闭 - 利用多态实现计算机
//实现计算器抽象类--不写功能
class AbstractCalculator {
public:
//父类中需要有虚函数,再在子类中进行重写
virtual int getResult() {
return 0;
}
int m_Num1;
int m_Num2;
};
//加法计算器类
class AddCaluculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 + m_Num2;
}
};
//减法计算器类
class SubCaluculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 - m_Num2;
}
};
//乘法计算器类
class MulCaluculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 * m_Num2;
}
};
int main() {
//多态使用条件
//父类指针或者引用指向子类对象
//加法:
AbstractCalculator * abc = new AddCaluculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "+" << abc->m_Num2 << abc->getResult << endl;
//用完后记得销毁
delete abc;
//减法
abc = new SubCaluculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "-" << abc->m_Num2 << abc->getResult << endl;
//用完后记得销毁
delete abc;
//乘法:
AbstractCalculator * abc = new MulCaluculator;
abc->m_Num1 = 10;
abc->m_Num2 = 20;
cout << abc->m_Num1 << "*" << abc->m_Num2 << abc->getResult << endl;
//用完后记得销毁
delete abc;
system("pause");
return 0;
}
- 多态好处:
1.组织结构清晰:–功能分块
2.可读性强
3.对于前期和后期扩展以及维护性高;