多态的基本概念
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 多态的基本概念
// 多态分为静态多态和动态多态
// 静态多态: 函数重载还运算符重载属于静态多态,服用函数名
// 动态多态: 派生派和虚函数实现运行时多态
//静态多态和动态多态的区别
// 静态多态的函数地址早绑定-编译阶段确定函数地址
// 动态多态的函数地址晚绑定-运行阶段确定函数地址
// 动态多态满足条件
// 1.有继承关系
// 2.子类重写父类的虚函数
// 重写就是:函数返回值类型 函数名 参数列表 完全相同
// 动态多态的使用
// 父类的指针或引用执行子类对象
// 动物类
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
// 猫类
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
// 执行说话的函数
// C++中允许父子之间的类型转换,不需要强制类型转换
void doSpeak(Animal &animal)
{
animal.speak();
}
void test01()
{
Cat c;
// 属于地址早绑定,在编译阶段确定函数地址
// 如果想执行让猫说话,那么这个函数地址就不能提前绑定。
// 需要在运行期间绑定,地址晚绑定
// 此时用到虚函数的概念,也就是在父类中的函数前加virtual
// 此作用是让被调用的类的说话函数优先执行,起始也就是加virtual降低了本身的优先级
// 子类中的virtual可写可不写
doSpeak(c); // 相当于 Animal &animal = c;
}
void doSpeak(Animal* animal)
{
animal->speak();
}
void test02()
{
Cat c;
doSpeak(&c);
}
int main()
{
test01();// 引用
test02();// 指针
system("pause");
return 0;
}
多态的原理剖析
此时该类中储存指向该函数的指针
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 多态的原理剖析
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
};
};
class Cat :public Animal
{
public:
//重写之后
void speak()
{
cout << "小猫在说话" << endl;
}
};
int main()
{
cout << "sizeof(Animal) = " << sizeof(Animal) << endl;
system("pause");
return 0;
}
多态案例一---- 计算器类
普通写法
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 计算器类普通写法
class Calculate
{
public:
Calculate(int num1,int num2)
{
this->num1 = num1;
this->num2 = num2;
}
int doWork(string operate)
{
if (operate == "+")
{
return num1 + num2;
}else if (operate == "-")
{
return num1 - num2;
}else if (operate == "*")
{
return num1 * num2;
}
// 此种写法如果想增加其它的功能,需要修改源码
// 在真正的开发中 提倡 开闭原则
// 开闭原则: 对扩展进行开放,对修改进行关闭
}
int num1;
int num2;
};
// 普通写法
void test01()
{
Calculate c(10, 20);
cout << c.num1 << "+" << c.num2 << " = " << c.doWork("+") << endl;
cout << c.num1 << "-" << c.num2 << " = " << c.doWork("-") << endl;
cout << c.num1 << "*" << c.num2 << " = " << c.doWork("*") << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
多态写法
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 计算器类-多态写法
// 多态的好处:
// 1.组织结构清晰
// 2.可读性强
// 3.对于前期和后期扩展以及维护性高
// C++开发提倡利用多态设计程序架构,因为多态优点很多
class AbstractCalculate
{
public:
int num1;
int num2;
virtual int calculate()
{
return 0;
}
};
class Add :public AbstractCalculate
{
public:
virtual int calculate()
{
return num1 + num2;
}
};
class Del :public AbstractCalculate
{
public:
virtual int calculate()
{
return num1 - num2;
}
};
class Cheng :public AbstractCalculate
{
public:
virtual int calculate()
{
return num1 * num2;
}
};
void test01()
{
// 多态使用条件
// 父类指针或引用指向子类对象
AbstractCalculate* c = new Add;
c->num1 = 10;
c->num2 = 20;
cout << c->num1 << " + " << c->num2 << " = " << c->calculate() << endl;
// 用完记得销魂
delete c;
c = new Del;
c->num1 = 10;
c->num2 = 20;
cout << c->num1 << " - " << c->num2 << " = " << c->calculate() << endl;
delete c;
}
int main()
{
test01();
system("pause");
return 0;
}
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现时毫无意义的,主要是调用子类重写的内容
因此可以将虚函数改为纯虚函数
当类中有了纯虚函数,这个类称为抽象类
抽象类特点:
1.无法实例化对象
2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 纯虚函数和抽象类
class Animal
{
public:
// 纯虚函数
// 只要有一个纯虚函数,这类就称为抽象类
// 抽象类特点
// 1.无法实例化对象
// 2.子类必须重写父类中的纯虚函数,否则无法实例化对象
virtual void func() = 0;
};
class Cat :public Animal
{
public:
void func()
{
cout << "func函数调用" << endl;
}
};
void test01()
{
//Animal a;
//new Animal; //抽象类是无法实例化对象的
Cat c;// 子类必须重写父类中的纯虚函数,否则无法实例化对象
Animal& animal = c;
animal.func();
}
int main()
{
test01();
system("pause");
return 0;
}
多态案例二:制作饮品
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class AbstraceMakeDrinking
{
public:
// 1.煮水
virtual void zhuShui() = 0;
// 2.冲泡
virtual void chongPao() = 0;
// 3.倒入杯中
virtual void daoRuBeiZhong() = 0;
// 4.加入辅料
virtual void jiaRuFuLiao() = 0;
void makeDrink()
{
zhuShui();
chongPao();
daoRuBeiZhong();
jiaRuFuLiao();
}
};
class kaFei :public AbstraceMakeDrinking
{
public:
// 1.煮水
virtual void zhuShui()
{
cout << "煮咖啡水" << endl;
}
// 2.冲泡
virtual void chongPao()
{
cout << "冲泡咖啡" << endl;
}
// 3.倒入杯中
virtual void daoRuBeiZhong()
{
cout << "导入咖啡杯中" << endl;
}
// 4.加入辅料
virtual void jiaRuFuLiao()
{
cout << "加入咖啡辅料" << endl;
}
};
void test01()
{
AbstraceMakeDrinking* coffee = new kaFei;
coffee->makeDrink();
delete coffee;
}
int main()
{
test01();
system("pause");
return 0;
}
虚析构和纯虚析构
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>
// 虚析构和纯虚析构
// 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时
//无法调用到子类的析构代码
// 因为父类引用指向子类对象,故在释放空间时调用的是父类的析构函数
// 故使用多态(虚析构或纯虚析构)
// 虚析构和纯虚析构的共性:
// 1.可以解决父类指针释放子类对象
// 2.都需要具体的函数实现
// 虚析构和纯虚析构的区别:
// 如果是纯虚析构,该类属于抽象类,无法实例化对象
// 总结
// 1.虚析构和纯虚析构就是用来解决父类指针释放子类对象
// 2.如果子类中没有堆区数据,可以不写虚析构或纯虚析构
// 3.拥有纯虚析构也属于抽象类
class Animal
{
public:
// 纯虚析构
virtual void speak() = 0;
Animal()
{
cout << "Animal类构造函数的调用" << endl;
}
利用虚析构可以解决 父类指针释放子类对象时不干净的问题
//virtual ~Animal()
//{
// cout << "Animal类析构函数的调用" << endl;
//}
// 纯虚析构(需要声明也需要实现)
// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
virtual ~Animal() = 0;
};
// 子类中需要析构函数释放空间,但是多态走不到子类中的析构函数,
// 所以需要虚析构和纯虚析构
Animal:: ~Animal()
{
cout << "Animal类析构函数的调用" << endl;
}
class Cat :public Animal
{
public:
string* name;
Cat(string name)
{
cout << "Cat类构造函数的调用" << endl;
this->name = new string(name);
}
~Cat()
{
cout << "Cat类析构函数的调用" << endl;
if (name != NULL)
{
delete name;
name = NULL;
}
}
virtual void speak()
{
cout << *name << "小猫在说话" << endl;
}
};
void test01()
{
// 多态:父类指针或引用指向子类对象
// 引用:给变量取别名
Animal *animal = new Cat("Tom");
animal->speak();
// 父类指针在析构的时候,不回调用子类中析构函数,
// 导致子类如果有堆区属性,出现内存泄露
delete animal;
animal = NULL;
}
int main()
{
test01();
system("pause");
return 0;
}
// 父类指针在析构的时候,不回调用子类中析构函数,
// 导致子类如果有堆区属性,出现内存泄露
// 解决方法,将父类析构函数改为虚析构或纯虚析构
多态案例三: 电脑组装
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// CPU抽象类
class Cpu
{
public:
virtual void calculate() = 0;
};
// 显卡抽象类
class DisplayCard
{
public:
virtual void display() = 0;
};
// 内存抽象类
class Memory
{
public:
virtual void distory() = 0;
};
// 电脑类
class Computer
{
public:
// 用来接受每一个零件
Computer(Cpu *cpu, DisplayCard *card, Memory *memory)
{
this->cpu = cpu;
this->card = card;
this->memory = memory;
}
~Computer()
{
if (cpu != NULL)
{
delete cpu;
cpu = NULL;
}
if (card != NULL)
{
delete card;
card = NULL;
}
if (memory != NULL)
{
delete memory;
memory = NULL;
}
}
// 用来协同每一个零件工作
void work()
{
cpu->calculate();
card->display();
memory->distory();
}
private:
Cpu* cpu;
DisplayCard* card;
Memory* memory;
};
// 不同厂商的CPU
class IntelCpu :public Cpu
{
public:
virtual void calculate()
{
cout << "Intel的CPU开始计算了" << endl;
}
};
class LevoeCpu :public Cpu
{
public:
virtual void calculate()
{
cout << "Levoe的CPU开始计算了" << endl;
}
};
// 不同厂商的显卡
class IntelDisplayCard :public DisplayCard
{
public:
virtual void display()
{
cout << "Intel的显卡开始显示了" << endl;
}
};
class LevoeDisplayCard :public DisplayCard
{
public:
virtual void display()
{
cout << "Levoe的显卡开始显示了" << endl;
}
};
//不同厂商的内存条
class IntelMemory :public Memory
{
public:
virtual void distory()
{
cout << "Intel的内存条开始存储了 " << endl;
}
};
class LevoeMemory :public Memory
{
public:
virtual void distory()
{
cout << "Levoe的内存条开始存储了 " << endl;
}
};
void test01()
{
// 第一台电脑运行
cout << "第一台电脑运行--------------------------" << endl;
Cpu* cpu = new IntelCpu;
DisplayCard* card = new IntelDisplayCard;
Memory* memory = new IntelMemory;
Computer *c = new Computer(cpu,card,memory);
c->work();
delete c;
// 第二台电脑运行
cout << "第二台电脑运行--------------------------" << endl;
c = new Computer(new LevoeCpu, new LevoeDisplayCard, new LevoeMemory);
c->work();
delete c;
c = NULL;
}
int main()
{
test01();
system("pause");
return 0;
}