多态的基本概念
多态是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;
}
}
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.对于前期和后期扩展以及维护性高;
|