多态的基本概念
多态是c++面向对象的三大特性之一
多态分为两类:静态多态和动态多态
静态多态:函数重载,运算符重载,复用函数名
动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态的区别:
静态多态函数地址早绑定------在编译阶段确定函数地址
动态多态函数地址晚绑定------在运行阶段确定函数地址
//多态基本概念
class Animal {
public:
//virtual关键字把函数变为虚函数 目的是让函数地址晚绑定,在运行时才确定
virtual void speken() {
cout << "动物在说话" << endl;
}
};
//函数重写:返回值类型、函数名、参数都一致
//函数重写和重载不一样,重载不用返回值类型来区分
class Cat :public Animal {
public:
//重写父类成员函数
void speken() {
cout << "小猫在说话" << endl;
}
};
class Dog :public Animal {
public:
//重写父类成员函数
void speken() {
cout << "小狗在说话" << endl;
}
};
//父类可以引用子类
//父类的引用,使子类可以任意变换,虚函数提供运行时确定
//如果不是虚函数,则函数在定义时,如donwu.speken();已经确定了其指向(父类)
void DoSpeak(Animal& donwu) {
donwu.speken();
}
//多态使用条件:父类指针或引用指向子类对象
void test01() {
Cat coke;
DoSpeak(coke);
Dog gg;
DoSpeak(gg);
}
int main()
{
test01();
}
下面通过案例讲解
多态案例1---计算机器
//多态案例:计算器实现
//普通写法
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;
};
void test01() {
Calculator count;
count.m_Num1 = 10;
count.m_Num2 = 10;
cout << count.m_Num1 << "+" << count.m_Num2 << "=" << count.getResult("+") << endl;
cout << count.m_Num1 << "-" << count.m_Num2 << "=" << count.getResult("-") << endl;
cout << count.m_Num1 << "*" << count.m_Num2 << "=" << count.getResult("*") << endl;
}
//多态方法(提倡)
//先提供一个抽象类
class AbstractCalculator {
public:
virtual int getResult() {
return 0;
}
int m_Num1;
int m_Num2;
};
//创建加法计算器
class Addcalculator:public AbstractCalculator {
public:
int getResult() {
return m_Num1 + m_Num2;
}
};
//创建减法计算器
class SubCalculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 - m_Num2;
}
};
//创建乘法计算器
class MulCalculator :public AbstractCalculator {
public:
int getResult() {
return m_Num1 * m_Num2;
}
};
void test02() {
//父类的指针或引用指向子类对象
AbstractCalculator* abc = new Addcalculator;
abc->m_Num1 = 100;
abc->m_Num2 = 100;
cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
//用完记得销毁数据
delete abc;
abc = new SubCalculator;
abc->m_Num1 = 100;
abc->m_Num2 = 100;
cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;
delete abc;
abc = new MulCalculator;
abc->m_Num1 = 100;
abc->m_Num2 = 100;
cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;
delete abc;
}
int main()
{
//开闭原则:打开扩展 关闭修改
//test01();
test02();
}
纯虚函数和抽象类
//类中只要有一个纯虚函数就称作抽象类
//抽象类无法实例化对象
//子类继承后必须重写父类的纯虚函数,不然也属于抽象类
class Base {
public:
virtual void func() = 0;//纯虚函数
};
class Son :public Base {
public:
virtual void func() {
cout << "子类重写纯虚函数" << endl;
}
};
void test01() {
//Base base;抽象类无法实例化对象
//new Base;栈区堆区中都不行
Son s;
s.func();
}
int main()
{
test01();
}
下面再通过一个案例巩固
多态案例2---制作饮品
//多态案例:制作饮品
class AbstractDrinking {
public:
//煮水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒入杯中
virtual void PourInCup() = 0;
//加入辅料
virtual void PutSomething() = 0;
//制作饮品
void makeDrink() {
Boil();
Brew();
PourInCup();
PutSomething();
}
};
//制作咖啡
class Coffee :public AbstractDrinking {
public:
//煮水
virtual void Boil() {
cout << "煮泉水" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲泡咖啡" << endl;
}
//倒入杯中
virtual void PourInCup() {
cout << "倒入杯中" << endl;
}
//加入辅料
virtual void PutSomething() {
cout << "加入糖和牛奶" << endl;
}
};
//制作茶水
class Tea :public AbstractDrinking {
public:
//煮水
virtual void Boil() {
cout << "煮泉水" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲泡茶叶" << endl;
}
//倒入杯中
virtual void PourInCup() {
cout << "倒入杯中" << endl;
}
//加入辅料
virtual void PutSomething() {
cout << "加入菊花" << endl;
}
};
void DoWork(AbstractDrinking* abs) {//父类指针或引用指向子类对象
abs->makeDrink();
delete abs;//堆区数据记得释放
}
void test01()
{
DoWork(new Coffee);
cout << "----------" << endl;
DoWork(new Tea);
}
int main()
{
test01();
}
虚析构和纯虚析构
//虚析构和纯虚析构
class Animal {
public:
Animal() {
cout << "Animal构造函数调用" << endl;
}
virtual void speak() {
cout << "动物在叫" << endl;
}
//当你有一个指向派生类对象的基类指针,(纯)虚析构函数确保了这个对象被删除时调用了基类析构函数后也会调用派生类析构函数
// 这样就解决了子类中也开辟了堆区数据的情况
//虚析构
/*virtual~Animal() {
cout << "Animal析构函数调用" << endl;
}*/
//纯虚析构(需类内声明,类外定义)
virtual~Animal() = 0;
};
Animal::~Animal() {
cout << "Animal析构函数调用" << endl;
}
class Cat :public Animal {
public:
Cat(string name) {
m_Name = new string(name);
cout <<"Cat构造函数调用" << endl;
}
virtual void speak() {
cout << *m_Name << "小猫在叫" << endl;
}
~Cat() {
if(m_Name!=NULL)
{
cout << "cat析构函数调用" << endl;
delete m_Name;
m_Name = NULL;
}
}
private:
string* m_Name;
};
void test01() {
Animal* animal = new Cat("Tom");
animal->speak();
delete animal;
//父类的指针或引用指向子类对象 要让其指向子类析构函数,得将父类析构函数变为虚析构或者纯虚析构
}
int main()
{
test01();
}