目录
基本概念
c++面向对象三大特性之一
分为两类:
静态多态:函数重载和运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
区别:
静态多态的函数地址早绑定 编译阶段确定函数地址
动态多态的函数地址晚绑定,运行阶段确定函数地址
动态多态满足条件
1、有继承关系
2、子类重写父类的虚函数
动态多态使用:
父类的指针或者引用 执行子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
#include <iostream>
using namespace std;
#include<string>
//多态
//动物类
class Animal {
public:
//虚函数
virtual void speak() {
cout << "小动物在说话" << endl;
}
};
//重写:函数返回值类型 函数名 参数列表 完全一致称为重写
class Cat:public Animal {
public:
void speak() {
cout << "小猫在说话" << endl;
}
};
//地址早绑定,在编译阶段就确定函数地址
//动态多态满足条件
//1、有继承关系
//2、子类重写父类的虚函数
//动态多态使用:父类的指针或者引用 执行子类对象
void dospeak(Animal &animal) {
animal.speak();
}
//如果想执行猫说话,地址就不能早绑定,需要在运行阶段进行绑定,在父类中加入virtual,改为虚函数
void test() {
Cat cat;
dospeak(cat);
}
int main() {
test();
system("pause");
return 0;
}
复习,只有非静态成员变量存储于类,静态函数和成员,非静态函数都不存储于类
多态的优点:
1 代码组织结构清晰
2 可读性强
3 利于前期和后期的扩展以及维护
在真实开发中,提倡开闭原则:对扩展进行开放,对修改进行关闭
c++开发提倡利用多态设计程序架构
案例一:利用多态实现计算器
#include <iostream>
using namespace std;
#include<string>
//利用多态实现计算器
//抽象计算器基类
class AbstractCaculator {
public:
virtual int getResult() {
return 0;
}
int m_a;
int m_b;
};
class Addcaculator :public AbstractCaculator {
int getResult() {
return m_a + m_b;
}
};
class Subcaculator :public AbstractCaculator {
int getResult() {
return m_a - m_b;
}
};
class Mulcaculator :public AbstractCaculator {
int getResult() {
return m_a * m_b;
}
};
void test01() {
AbstractCaculator* abc = new Addcaculator;
abc->m_a = 100;
abc->m_b = 20;
int result = abc->getResult();
cout << result << endl;
}
int main() {
test01();
system("pause");
return 0;
}
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数
纯虚函数语法: virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也成为抽象类
抽象类特点:
无法实例化对象
子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include <iostream>
using namespace std;
#include<string>
// 抽象类 无法实例化对象
class Base {
public:
virtual void func() = 0;
};
class Son :public Base {
public:
virtual void func() {
cout << "func函数的调用" << endl;
}
};
void test01() {
//Base a; 报错,抽象类 无法实例化对象
//new Base;报错,抽象类 无法实例化对象
Base* son = new Son;
son->func();
delete son;
}
int main() {
test01();
system("pause");
return 0;
}
案例二:制作饮品
#include <iostream>
using namespace std;
#include<string>
//多态案例2 制作饮品
class AbstractDrink {
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 AbstractDrink {
public:
//煮水
virtual void Boil() {
cout << "煮农夫山泉" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲咖啡" << endl;
}
//倒入杯中
virtual void PourInCup() {
cout << "倒入咖啡杯" << endl;
}
//加入辅料
virtual void PutSomething() {
cout << "倒入糖和牛奶" << endl;
}
};
class Tea :public AbstractDrink {
public:
//煮水
virtual void Boil() {
cout << "煮矿泉水" << endl;
}
//冲泡
virtual void Brew() {
cout << "冲茶叶" << endl;
}
//倒入杯中
virtual void PourInCup() {
cout << "倒入茶杯" << endl;
}
//加入辅料
virtual void PutSomething() {
cout << "放入柠檬片" << endl;
}
};
//制作函数
void dowork(AbstractDrink * abs) {
abs->makeDrink();
delete abs;
}
void test01() {
//制作咖啡
dowork(new Coffee);
cout << "-----------------------" << endl;
//制作茶
dowork(new Tea);
}
int main() {
test01();
system("pause");
return 0;
}
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,导致子类如果有堆区属性,出现内存泄漏现象
解决方式:将父类中的析构函数改为虚析构或纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
#include <iostream>
using namespace std;
#include<string>
class Animal {
public:
Animal() {
cout << "animal构造函数调用" << endl;
}
//利用虚析构解决父类指针释放子类对象释放不干净的问题
virtual~Animal() {
cout << "animal虚析构函数调用" << endl;
}
//纯虚函数
virtual void speak() = 0;
};
class Cat :public Animal {
public:
Cat(string name) {
cout << "cat构造函数调用" << endl;
m_name = new string(name); // new,返回的是指针
}
~Cat() {
cout << "cat析构函数调用" << endl;
if (m_name != NULL) {
delete m_name;
m_name = NULL;
}
}
virtual void speak() {
cout <<*m_name<< "小猫在说话" << endl;
}
string* m_name;
};
void test01() {
Animal* animal = new Cat("tom");
animal->speak();
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
纯虚析构语法:
virtual ~类名()=0;
类名::~类名(){}
#include <iostream>
using namespace std;
#include<string>
class Animal {
public:
Animal() {
cout << "animal构造函数调用" << endl;
}
利用虚析构解决父类指针释放子类对象释放不干净的问题
//virtual~Animal() {
// cout << "animal虚析构函数调用" << endl;
//}
//纯虚析构 需要声明也需要实现
virtual ~Animal() = 0;
//纯虚函数
virtual void speak() = 0;
};
//具体实现
Animal::~Animal() {
cout << "animal纯虚析构函数调用" << endl;
}
class Cat :public Animal {
public:
Cat(string name) {
cout << "cat构造函数调用" << endl;
m_name = new string(name); // new,返回的是指针
}
~Cat() {
cout << "cat析构函数调用" << endl;
if (m_name != NULL) {
delete m_name;
m_name = NULL;
}
}
virtual void speak() {
cout <<*m_name<< "小猫在说话" << endl;
}
string* m_name;
};
void test01() {
Animal* animal = new Cat("tom");
animal->speak();
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
总结:
虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
拥有纯虚析构函数的类也属于抽象类,不能实例化对象
案例三 电脑组装
案例描述:组成部件:CPU 显卡 内存条
将每个零件封装抽象基类,并提供不同厂商生产不同的零件
创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装三台不同的电脑进行工作
#include <iostream>
using namespace std;
#include<string>
//案例 电脑组装
//抽象不同零件类
///CPU
class CPU{
public:
virtual void caculate() = 0;
};
//显卡
class VideoCard{
public:
virtual void display() = 0;
};
//内存条
class Memory {
public:
virtual void storage() = 0;
};
//抽象类不能实例化,但是可以创建指针
class Computer {
public:
Computer(CPU* cpu,VideoCard*vc,Memory*memory) {
m_cpu = cpu;
m_videocard = vc;
m_memory = memory;
}
//提供让零件工作的接口
void dowork() {
m_cpu->caculate();
m_videocard->display();
m_memory->storage();
}
~Computer() {
if (m_cpu != NULL) {
delete m_cpu;
m_cpu = NULL;
}
if (m_videocard != NULL) {
delete m_videocard;
m_videocard = NULL;
}
if (m_memory != NULL) {
delete m_memory;
m_memory = NULL;
}
}
private:
CPU* m_cpu;
VideoCard* m_videocard;
Memory* m_memory;
};
//具体厂商
class IntelCpu:public CPU{
public:
virtual void caculate() {
cout << "Intel的cpu开始计算了" << endl;
}
};
class IntelVideoCard :public VideoCard {
public:
virtual void display() {
cout << "Intel的VideoCard开始显示了" << endl;
}
};
class InteMemory :public Memory {
public:
virtual void storage() {
cout << "lenovo的Memory开始存储了" << endl;
}
};
class lenovoCpu :public CPU {
public:
virtual void caculate() {
cout << "lenovo的cpu开始计算了" << endl;
}
};
class lenovoVideoCard :public VideoCard {
public:
virtual void display() {
cout << "lenovo的VideoCard开始显示了" << endl;
}
};
class lenovoMemory :public Memory {
public:
virtual void storage() {
cout << "lenovo的Memory开始存储了" << endl;
}
};
void test01() {
//创建3电脑
//第一台电脑
CPU* intelCpu = new IntelCpu;
VideoCard* intelVedioCard = new IntelVideoCard;
Memory* intelMemory = new InteMemory;
Computer* computer1 = new Computer(intelCpu,intelVedioCard,intelMemory);
computer1->dowork();
delete computer1;
//第二台电脑
cout << "第二台电脑" << endl;
Computer* computer2 = new Computer(new lenovoCpu,new lenovoVideoCard,new lenovoMemory);
computer2->dowork();
delete computer2;
//第三台电脑
cout << "第三台电脑" << endl;
Computer* computer3 = new Computer(new IntelCpu, new lenovoVideoCard, new lenovoMemory);
computer3->dowork();
delete computer3;
}
int main() {
test01();
system("pause");
return 0;
}