多态的概念
多态的分类
静态多态:函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别:
静态多态的函数地址早绑定 - 编译阶段确定函数地址
动态多态的函数地址晚绑定 - 运行阶段确定函数地址
案例:
(1)无虚函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Father { public: void speak() { std::cout << "父亲说话" << std::endl; } }; class Son1:public Father { public: void speak() { std::cout << "儿子1说话" << std::endl; } };
void doSpeak(Father &f) { f.speak(); } int main() { std::cout << sizeof(Father) << std::endl; Son1 s1; doSpeak(s1); return 0; }
|
(2)虚函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| class Father { public: virtual void speak() { std::cout << "父亲说话" << std::endl; } }; class Son1:public Father { public: void speak ()override { std::cout << "儿子1说话" << std::endl; } }; class Son2:public Father { public: void speak ()override { std::cout << "儿子2说话" << std::endl; } }; class Sun1:public Son1 { public: void speak()override { std::cout << "孙子1说话" << std::endl; } };
void doSpeak(Father &f) { f.speak(); } int main() { std::cout << sizeof(Father) << std::endl; Son1 s1; doSpeak(s1); Father f; doSpeak(f); Son2 s2; doSpeak(s2); Sun1 su1; doSpeak(su1); return 0; }
|
动态多态的满足条件:(1)有继承的关系(2)子类重写父类的虚函数
重写:子类继承父类后,函数返回值类型、函数名、参数列表完全相同;
重载:同一个类中,函数名相同,参数列表不同的几个函数,与返回值无关。//同名不同参,是重载
动态多态的使用:父类的指针或者引用,指向子类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| class Father { private: std::string name; int age; public: Father():name{},age{}{} Father(std::string name,int age):name{name},age{age}{} void setName(std::string name) { this->name = name; } std::string getName() const { return name; } void setAge(int age) { this->age = age; } int getAge() const { return age; } virtual void desc() { std::cout << name << age << std::endl; } };
class Son1:public Father { private: double salary; public: Son1():salary{},Father{}{} Son1(std::string name,int age,double salary):salary{salary},Father{name,age}{} double getSalary()const { return salary; } void setSalary(double salary) { this->salary = salary; } void desc()override { std::cout << getName() << getAge() << salary << std::endl; }
};
class Son2:public Father { private: double score; public: Son2():score{},Father{}{} Son2(std::string name,int age,double score):score{score},Father{name,age}{} double getScore()const { return score; } void setScore(double score) { this->score = score; } void desc()override { std::cout << getName() << getAge() << score << std::endl; } }; void getDesc(Father &f) { f.desc(); } int main() { Father f{"zs",50}; Son1 s1{"z1",30,7000}; Son2 s2{"z2",16,80}; getDesc(f); getDesc(s1); getDesc(s2); return 0; }
|
多态原理

案例:
计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class AbstractCalculator { public: int num1; int num2; virtual int getResult() { return 0; } }; class Add:public AbstractCalculator { public: int getResult()override { return num1 + num2; } }; class Sub:public AbstractCalculator { public: int getResult()override { return num1 - num2; } }; class Mul:public AbstractCalculator { public: int getResult()override { return num1 * num2; } }; int main() { AbstractCalculator *abc = new Add; abc->num1 = 10; abc->num2 = 20; std::cout << abc->getResult() << std::endl; }
|
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内
因此可以将虚函数改为纯虚函数
1
| 格式: virtual 返回值类型 函数名(参数列表)= 0;
|
当类中有了纯虚函数,这个类也称为 抽象类
纯虚函数一般不用实现,但如果提供实现的话,必须在类外定义
抽象类特点:
(1)无法实例化对象,并不意味着他没有对象,他的对象包括在子类里面
(2)子类必须重写抽象类中的纯虚函数,否则子类也属于抽象类
1 2 3 4 5 6 7
| class AbstractCalculator { public: int num1; int num2; virtual int getResult()=0; };
|
每个子类对象在构造过程中,必优先构造父类的对象,构造父类的对象必先调用父类的构造函数
案例
制作饮品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| class AbstractDrinking { public: virtual void boil() = 0; virtual void brew() = 0; virtual void pourInCup() = 0; virtual void putSomething() = 0; void markDirnk() { boil(); brew(); pourInCup(); putSomething(); } virtual ~AbstractDrinking(){} }; class Coffee:public AbstractDrinking { public: virtual void boil()override { std::cout << "煮山泉" << std::endl; } virtual void brew()override { std::cout << "冲咖啡" << std::endl; } virtual void pourInCup()override { std::cout << "将咖啡倒入杯中" << std::endl; } virtual void putSomething()override { std::cout << "加糖加奶" << std::endl; } }; class Tea:public AbstractDrinking { public: virtual void boil()override { std::cout << "煮井水" << std::endl; } virtual void brew()override { std::cout << "冲菊花茶" << std::endl; } virtual void pourInCup()override { std::cout << "将茶水倒入杯中" << std::endl; } virtual void putSomething()override { std::cout << "加枸杞" << std::endl; } };
void doWork(AbstractDrinking& drink) { drink.markDirnk(); } int main() { Coffee cof; doWork(cof); Tea t; doWork(t); return 0; }
|
虚析构和纯虚析构
多态使用时,如果父类析构函数不是虚拟的,那么在对象回收时,父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
1 2 3 4
| 虚析构语法: virtual ~类名(){} 纯虚析构语法: virtual ~类名() = 0; 类名::~类名(){}
|
什么时候需要把父类的析构函数变为纯虚析构:我这类本身没有纯虚函数,但是想让这个类成为抽象类
纯虚析构函数的实现通常在类的定义外部提供,以确保派生类在实现自己的析构函数时能够调用基类的析构函数。这样做是为了保证在销毁派生类对象时能正确地执行基类和派生类的清理操作。
案例
电脑组装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| class CPU { public: virtual void calculate() = 0; virtual ~CPU(){} }; class VideoCard { public: virtual void display() = 0; virtual ~VideoCard(){} }; class Memory { public: virtual void storage() = 0; virtual ~Memory(){} };
class IntelCPU:public CPU { public: virtual void calculate() { std::cout << "IntelCPU开始计算" << std::endl; } }; class IntelVideoCard:public VideoCard { public: virtual void display() { std::cout << "Intel显卡开始显示" << std::endl; } }; class IntelMemory:public Memory { public: virtual void storage() { std::cout << "Intel内存条开始存储" << std::endl; } };
class LenovoCPU:public CPU { public: virtual void calculate() { std::cout << "LenovoCPU开始计算" << std::endl; } }; class LenovoVideoCard:public VideoCard { public: virtual void display() { std::cout << "Lenovo显卡开始显示" << std::endl; } }; class LenovoMemory:public Memory { public: virtual void storage() { std::cout << "Lenovo内存条开始存储" << std::endl; } };
class Commputer { private: CPU* m_cpu; VideoCard* m_mv; Memory* m_mem; public: Commputer(CPU* cpu,VideoCard* mv,Memory* mem) { m_cpu = cpu; m_mv = mv; m_mem = mem; } void work() { m_cpu->calculate(); m_mv->display(); m_mem->storage(); } ~Commputer() { if(m_cpu != nullptr) { delete m_cpu; m_cpu = nullptr; } if(m_mv != nullptr) { delete m_mv; m_mv = nullptr; } if(m_mem != nullptr) { delete m_mem; m_mem = nullptr; } } }; int main() { CPU* intelCPU = new IntelCPU; VideoCard* intelCard = new IntelVideoCard; Memory* intelMemory = new IntelMemory; Commputer* comm1 = new Commputer(intelCPU,intelCard,intelMemory); comm1->work(); delete comm1; Commputer* comm2 = new Commputer(new LenovoCPU,new LenovoVideoCard,new LenovoMemory); comm2->work(); delete comm2;
return 0; }
|