多态介绍
面向对象三大特性之一, 多态分类
- 静态多态:函数重载 和 运算符重载 属于静态多态,复用函数名
- 动态多态:派生类 和 基类 实现运行时多态 静态动态多态区别:
- 多态的函数地址早绑定——编译阶段确定函数地址
- 多态的函数地址晚绑定——运行阶段确定函数地址
class Animal
{
public:
virtual void speak()//虚函数 //多态核心1virtual 地址晚绑定——运行阶段绑定
{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.speak();}///多态核心2Animal &animal = [cat/dog];
int main()
{
Cat cat;
Dog dog;
doSpeak(cat);
dospeak(dog);
//output:小猫在说话
//小狗在说话
return 0;
}title:Example
collapse:openclass Animal
{
public:
void speak()
{cout << "动物在说话" << endl;}
};
class Cat:public Animal
{
public:
void speak()
{cout << "小猫在说话" << endl;}
};
class
void doSpeak(Animal &animal)
{animal.speak();}//Animal &animal = cat;
int main()
{
Cat cat;
doSpeak(cat);
//output:动物在说话
return 0;
}title:Summary
collapse:open
~~~ad-example
title:重载
collapse:open
同一作用域(同一文件)
函数名相同
函数参数类型不同,个数不同,顺序不同
与函数返回值类型无关
~~~
<br>
<br>
~~~ad-example
title:重写
collapse:open
通常为子类重写父类虚函数
函数返回值类型 函数名 参数列表 完全相同
- 重写是与多态相关的应用方式
父类指针或者引用 执行子类对象
~~~原理简单刨析
多态原理图解
⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠
Text Elements
class Animal { public: virtual void speak() {cout << “动物在说话” << endl;} };
vfptr - 虚函数指针 v - virtual f - function ptr - pointer
Animal 内部结构 vfptr
vftable
vftable - 虚函数表 v - virtual f - function table - table
&Animal::speak
class Cat:public Animal { public: virtual void speak() {cout << “小猫在说话” << endl;} };
Cat 内部结构重写Animal之后 vfptr
vftable
&Cat::speak
Embedded files
0e79c74740a2ce26c3070c8007fb1928a4203136: 4b9af544de6ca83bebe9f4c04965f89600c97621:
指向原始笔记的链接
具体案例
cpp多态案例
title:猫狗说话 collapse:open ```cpp #include <iostream> using namespace std; class Animal { public: virtual void speak()//虚函数 //多态核心1virtual 地址晚绑定——运行阶段绑定 {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.speak();}///多态核心2Animal &animal = [cat/dog]; int main() { Cat cat; Dog dog; doSpeak(cat); dospeak(dog); //output:小猫在说话 //小狗在说话 return 0; }title:不利用多态 collapse:open 设计计算器 ```cpp #include<iostream> using namespace std; enum TYPE { ADD, DEC, MULT, DIV }; class Calculator { public: int getResult(std::string oper) { switch(oper) { case '+':return m_num1 + m_num2; case '-':return m_num1 - m_num2; case '*':return m_num1 * m_num2; case '/':return m_num1 / m_num2; default:break; } } private: int m_num1, m_num2; }; int main() { Calculator c; c.m_num1 = 10; c.m_num2 = 10; cout << c.m_num1 << '+' << c.m_num2 << '=' << c.getResult("+") << endl; //output:10+10=20 return 0; }title:利用多态设计计算器 collapse:open ```cpp #include <iostream> using namespace std; 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 multCalculator :public AbstractCalculator { public: int getResult(){return m_num1 * m_num2;} }; class divCalculator :public AbstractCalculator { public: int getResult(){return m_num1 / m_num2;} }; int main() { AbstractCalculator *abc = new addCalculator; abc->m_num1 = 100; abc->m_num2 = 100; cout << abc->getResult() << endl; delete abc; abc = new subCalculator; abc->m_num1 = 100; abc->m_num2 = 100; cout << abc->getResult() << endl; delete abc; abc = new multCalculator; abc->m_num1 = 100; abc->m_num2 = 100; cout << abc->getResult() << endl; delete abc; abc = new divCalculator; abc->m_num1 = 100; abc->m_num2 = 100; cout << abc->getResult() << endl; delete abc; /*output: 200 0 10000 1 */ }title:制作饮品 collapse:open ```cpp #include <iostream> using namespace std; 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: void boil() /// 煮水 { cout << "煮农夫山泉" << endl; } void brew() /// 冲泡 { cout << "冲泡咖啡" << endl; } void pourInCup() /// 倒入杯中 { cout << "倒入杯中" << endl; } void putSomething() /// 加入辅料 { cout << "加入糖和牛奶" << endl; } void makeDrink() { boil(); brew(); pourInCup(); putSomething(); } }; class Tea: public AbstractDrinking { public: void boil() /// 煮水 { cout << "煮农夫山泉" << endl; } void brew() /// 冲泡 { cout << "冲泡茶" << endl; } void pourInCup() /// 倒入杯中 { cout << "倒入杯中" << endl; } void putSomething() /// 加入辅料 { cout << "加入枸杞" << endl; } void makeDrink() { boil(); brew(); pourInCup(); putSomething(); } }; //制作函数 void doWork(AbstractDrinking* abs) { abs->makeDrink(); delete abs; } int main() { doWork(new Coffee); /*output: 煮农夫山泉 冲泡咖啡 倒入杯中 加入糖和牛奶*/ cout << "-------------" << endl; doWork(new Tea); /*output: ------------- 煮农夫山泉 冲泡茶 倒入杯中 加入枸杞 */ return 0; }指向原始笔记的链接 title:多态电脑 collapse:open ```cpp #include <iostream> using namespace std; class CPU { public: virtual void calculate() = 0; }; class GPU { public: virtual void display() = 0; }; class RAM { public: virtual void storage() = 0; }; class Computer { public: Computer(CPU* cpu, GPU* gpu, RAM* ram) { m_cpu = cpu; m_gpu = gpu; m_ram = ram; } void work() { m_cpu->calculate(); m_gpu->display(); m_ram->storage(); } ~Computer() { if(m_cpu != NULL) { delete m_cpu; m_cpu = NULL; } if(m_gpu != NULL) { delete m_gpu; m_gpu = NULL; } if(m_ram != NULL) { delete m_ram; m_ram = NULL; } } private: CPU* m_cpu; GPU* m_gpu; RAM* m_ram; }; //Inter class IntelCPU: public CPU { public: virtual void calcutale(){cout << "IntelCPUstartCalculate" << endl;} }; class IntelGPU: public GPU { public: virtual void display(){cout << "IntelGPUstartDisplay" << endl;} }; class IntelRAM: public RAM { public: virtual void storage(){cout << "IntelRAMstartStorage" << endl;} }; //Lenovo class LenovoCPU: public CPU { public: virtual void calcutale(){cout << "LenovoCPUstartCalculate" << endl;} }; class LenovoGPU: public GPU { public: virtual void display(){cout << "LenovoGPUstartDisplay" << endl;} }; class LenovoRAM: public RAM { public: virtual void storage(){cout << "LenovoGPUstartStorage" << endl;} }; void test01() { CPU* intelcpu = new IntelCPU; GPU* intelgpu = new IntelGPU; RAM* intelram = new IntelRAM; //组装第一台电脑 Computer* computer1 = new Computer(intelcpu, intelgpu, intelram); conputer1->work(); delete conputer1; //组装第二台电脑 Computer* computer2 = new Computer( new LenovoCPU, new LenovoGPU, new LenovoRAM ); conputer2->work(); delete conputer2; //组装第三台电脑 Computer* computer3 = new Computer( new LenovoCPU, new IntelGPU, new LenovoRAM ); conputer3->work(); delete conputer3; } int main() { test01(); return 0; }
title:多态好处
collapse:open
- 组织结构逻辑清晰
- 可读性强
- 对于后期的扩展和可维护性高纯虚函数和抽象类(接口类)
纯虚函数
virtual 返回值类型 函数名(参数列表) = 0;
抽象类
当类中有了纯虚函数,这个类也称为抽象类(接口类)
title:抽象类特点
- 无法实例化对象(创建不了)
- 子类必须重写抽象类中的纯虚函数,否则也属于抽象类title:作用
- 编译器约束必须有子类实现
- 运行时多态
- 解耦title:Important
collapse:open
```cpp
class Base
{
public:
//纯虚函数
virtual void func() = 0;
};title:Error
collapse:open
```cpp
//from important
int main()
{
Base *b = new Base;//错误,无法实例化对象
}title:Error2
collapse:open
```cpp
//from important
class Son :public Base;
int main()
{
Son s;//错误,子类还未重写
}title:Success
collapse:open
```cpp
class Son :public Base
{
public:
virtual void func(){};//尽管没有写任何东西,但编译器依然认为已重写
};
class Son2 :public son
{
public:
virtual void func()
cout << "func()调用" << endl;
};
int main()
{
Son s;
Base *base = new Son2;
base->func();
//output:func()调用
}虚析构和纯虚析构
虚析构
virtual ~类名(){}
纯虚析构
virtual ~类名() = 0;
title:Important
collapse:open
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象title:warning
collapse:open
```cpp
class Animal
{
public:
Animal(string name){cout << "Animalgouzao" << endl;}
virtual void speak() = 0;
~Animal(){cout << "Animalxigou" << endl;}
};
class Cat: public Animal
{
public:
Cat(string name)
{
cout << "Catgouzao" << endl;
m_name = new string(name);
}
virtual void speak()
{cout << m_name << "miao" << endl;}
~Cat()
{
if(m_name != NULL)
{
cout << "xigou" << endl;
delete m_name;
m_name = NULL;
}
}
string *m_name;
};
class Dog: public Animal
{
public:
Dog(string name){cout << "Doggouzao" << endl;}
~Dog(){cout << "Dogxigou" << endl;}
void speak()
{cout << "wang" << endl;}
};
int main()
{
Animal *animal = new Cat("Tom");
animal->speak();
delete animal;
return 0;
}
/*output:
Animalgouzao
Catgouzao
Tommiao
Animalxigou
*/
//没有Cat子类析构title:Question
collapse:open
父类指针在析构时,不会调用子类析构,导致子类如果有堆区属性,出现内存泄漏
解决方法:父类析构改为虚析构title:Success
collapse:open
```cpp
//from warning
virtual ~Animal(){...}
//纯虚析构实现
//from warning
virtual ~Animal() = 0;
//outclass
Animal::~Animal()
{cout << "Animalxigou" << endl;}title:Summary
collapse:open
如果要创建一个指向父类的子类对象指针,建议父类析构使用纯虚析构