7.类和对象_多态
//多态的分类:静态多态和动态多态
//静态多态:函数重载和运算符重载属于静态多态,复用函数名
//动态多态:派生类和虚函数实现运行时多态
//区别:
// 静态:函数地址早绑定,编译阶段确定
// 动态:函数地址晚绑定,运行阶段确定
//动态多态条件:
// 1.有继承关系
// 2.重写父类的虚函数(不是重载,函数返回值类型,函数名,参数列表完全相同)
//对于子类重写时,子类的virtual关键字可写可不写
//动态多态的使用:
// 父类的指针或引用指向子类的对象
//纯虚函数和抽象类
//通常父类虚函数毫无意义,主要调用子类重写的内容
//因此可以将虚函数改写成纯虚函数
//语法:virtual 返回值类型 函数名 (参数列表) = 0;
//当类中有纯虚函数,这个类叫抽象类
//抽象类特点:1.无法实例化对象 2.子类必须重写抽象类的纯虚函数,否则也属于抽象类
//虚析构和纯虚析构
//共性:可以解决父类指针释放子类对象;都要有具体的函数实现
//区别:纯虚析构属于抽象类,无法实例化对象
//父类指针在析构时,不会调用子类的析构函数,导致子类如果有堆区属性,会内存泄漏
//利用虚析构可以解决父类指针释放子类对象时不干净的问题
//虚析构和纯虚析构都需要代码实现:
// 纯虚析构,在类的外部:类名::~类名(){代码实现}
//有纯虚析构后,这个类也属于抽象类,无法实例化对象
//使用条件:子类的析构是必需的
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
//virtual void speak()
//{
// cout << "Animal speaking" << endl;
//}
virtual void speak() = 0;
};
//Animal类内部
//vfptr - 虚函数(表)指针,指向vftable(表内部记录虚函数地址)
//Cat类内部
//vfptr指向vftable
//当子类重写父类的虚函数
//子类中的虚函数表内部会替换成子类的虚函数地址
class Cat :public Animal
{
public:
void speak()
{
cout << "Meow~" << endl;
}
};
class Dog :public Animal
{
public:
void speak()
{
cout << "Woof~" << endl;
}
};
void doSpeak(Animal &animal) //Animal& animal = cat; 相当于父类引用指向子类的对象
{
//当父类的指针或者引用指向子类对象时
//发生多态
//C++允许父子之间类型转换,不需要强制类型转换
//地址早绑定,在编译阶段就确定了地址
//如果想猫说话,那么函数地址就不能提前绑定,需要在运行时绑定
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
//真实开发中,提倡开闭原则
//对扩展开放,对修改关闭
//多态实现计算器
//计算器抽象类
//多态好处:
// -组织结构清晰
// -可读性强
// -对于前期和后期扩展以及维护性高
class CalcAbstract
{
public:
virtual int getResult() { return 0; }
int m_Num1;
int m_Num2;
};
class AddCalc :public CalcAbstract
{
public:
virtual int getResult()
{
return m_Num1 + m_Num2;
}
};
class SubCalc :public CalcAbstract
{
public:
virtual int getResult()
{
return m_Num1 - m_Num2;
}
};
class MulCalc :public CalcAbstract
{
public:
virtual int getResult()
{
return m_Num1 * m_Num2;
}
};
void test02()
{
//多态使用条件
//父类的指针或引用指向子类对象
CalcAbstract* cab = new AddCalc;
cab->m_Num1 = 10;
cab->m_Num2 = 10;
cout << cab->getResult() << endl;
delete cab;
cab = new SubCalc;
cab->m_Num1 = 10;
cab->m_Num2 = 10;
cout << cab->getResult() << endl;
delete cab;
cab = new MulCalc;
cab->m_Num1 = 10;
cab->m_Num2 = 10;
cout << cab->getResult() << endl;
delete cab;
}
int main()
{
//test01();
//test02();
system("pause");
return 0;
}