多态分为两类:
1,静态多态:函数重载和运算符重载属于静态多态,复用函数名
2,动态多态:派生类和虚函数实现运行时多态
静态和动态的区别:
1,静态多态函数的地址早绑定-编译阶段确定函数地址
2,动态多态函数地址晚绑定-运行阶段确定函数地址
#include<iostream>
using namespace std;
//2、定义一图形CShape类,其中有成员数据:宽度width和高度height,带构造函数。并建立两个派生类
//:矩形类和等腰三角形类。派生类中都包含一函数Area,分别用来计算矩形和等腰三角形的面积。
class Animal
{public://不要忘掉public
//前面加上virtual关键字变为虚函数,编译器在编译的时候就不能确定函数调用
virtual void speak()
{
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();
}
//动态多态满足的条件:
//1,有继承关系
//2,子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象
void test()
{
cat c;
dospeak(c);
dog d;
dospeak(d);
}
int main()
{
test();
return 0;
}
二,多态原理剖析
三,多态案列-计算机类
普通实现:
#include<iostream>
using namespace std;
class Calculator {
public:
int getresult(string oper)
{
if (oper == "+")
{
return m_Num1 + m_Num2;
}
if (oper == "-")
{
return m_Num1 - m_Num2;
}
if (oper == "*")
{
return m_Num1 * m_Num2;
}
}
public:
int m_Num1;
int m_Num2;
};
void test()
{
Calculator c;
c.m_Num1 = 10;
c.m_Num2 = 10;
cout << c.m_Num1 << "+" << c.m_Num2 << "=" << c.getresult("+") << endl;
cout << c.m_Num1 << "-" << c.m_Num2 << "=" << c.getresult("-") << endl;
cout << c.m_Num1 << "*" << c.m_Num2 << "=" << c.getresult("*") << endl;
}
int main()
{
test();
return 0;
}
多态实现:
#include<iostream>
using namespace std;
class Calculator {
public:
virtual int getresult()
{
return 0;
}
int m_Num1;
int m_Num2;
};
class addcalculator :public Calculator//派生类注意语法
{
public:
int getresult()
{
return m_Num1 + m_Num2;
}
};
class descalculator :public Calculator {
public:
int getresult()
{
return m_Num1 - m_Num2;
}
};
class mulcalculator :public Calculator {
public:
int getresult()
{
return m_Num1 * m_Num2;
}
};
int main()
{
Calculator* abc = new addcalculator;//父类指向子类
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << "+" << abc->m_Num2 << "="<<abc->getresult() << endl;
delete abc;//堆区手动开辟手动释放,用完即销毁
abc = new descalculator;//注意不要重定义
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getresult() << endl;
delete abc;//堆区手动开辟手动释放,用完即销毁
abc = new mulcalculator;//父类指向子类
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getresult() << endl;
delete abc;//堆区手动开辟手动释放,用完即销毁
return 0;
}
多态优点:
1,代码组织结构清晰
2,可读性强
3,利用前期和后期的扩展以及维
四,纯虚函数和抽象类
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也成为抽象类
抽象类特点:
1,无法实例化对象
2,子类必须重写抽象类中的纯虚函数,否则也属于抽象类
#include<iostream>
using namespace std;
class Base
{
public:
virtual void func() = 0;
};
class Son:public Base
{
public:
virtual void func()//必须重写父类中的纯虚函数
{
cout << "func调用" << endl;
}
};
void test()
{
Base* base = NULL;
//base=new Base;//错误,抽象类无法实例化对象
base = new Son;
base->func();
delete base;//记得销毁
}
int main()
{
test();
return 0;
}
五,多态动态化实例2制作饮品
案例描述:
制作饮品的大致流程分为:煮水-冲泡-倒入杯中-加入辅料
利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶;
个人实现代码:
#include<iostream>
using namespace std;
//制作饮品的大致流程分为:煮水 - 冲泡 - 倒入杯中 - 加入辅料
//
//利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶;
class Createdrink
{
public:
void zhushui()
{
cout << "煮水-";
}
void congpao()
{
cout << "冲泡-" ;
}
virtual void daobei()
{
cout << "倒入杯中-" ;
}
virtual void fuliao() = 0;
};
class coffee :public Createdrink {
virtual void fuliao()
{
cout << "加入咖啡" <<endl;
}
};
class tea :public Createdrink {
virtual void fuliao()
{
cout << "加入茶叶" << endl;
}
};
void test1()
{
Createdrink* base = NULL;
base = new coffee;
base->zhushui(); base->congpao(); base->daobei(); base->fuliao();
delete base;
}
void test2()
{
Createdrink* base = NULL;
base = new tea;
base->zhushui(); base->congpao(); base->daobei(); base->fuliao();
delete base;
}
int main()
{
cout << "泡咖啡流程:" << endl;
test1();
cout << "泡茶流程:"<<endl;
test2();
}
效果图:
实例代码:
#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 {
virtual void boil() {
cout << "煮农夫山泉" << endl;
}
virtual void brew()
{
cout << "冲咖啡" << endl;
}
virtual void pourincup() {
cout << "倒入瓷杯" << endl;
}
virtual void putsomething() {
cout << "加牛奶和糖" << endl;
}
};
class tea :public abstractdrinking {
virtual void boil() {
cout << "煮泉水" << endl;
}
virtual void brew()
{
cout << "冲茶叶" << endl;
}
virtual void pourincup() {
cout << "倒入玻璃杯" << endl;
}
virtual void putsomething() {
cout << "加柠檬" << endl;
}
};
void dowork(abstractdrinking* abs)//abstractdrinking*abs=new coffee建立接口
{
abs->makedrink();
delete abs;//注意释放
}
void test1()
{
dowork(new coffee);//连接接口
cout << "-------------------" << endl;
dowork(new tea);
}
int main()
{
test1();
return 0;
}
效果图:
六,虚析构和纯虚析构
共性:
1,可以解决父类指针释放子类对象
2,都需要有具体的函数实现
区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名()=0
类名::~类名(){}
class Animal {
public:
Animal() {
cout << "Animal构造函数调用!" << endl;
}
virtual void speak() = 0;
//析构函数加virtual关键字,变为虚析构函数
//virtual ~Animal(){
//cout<<"Animal虚构造函数调用!"<<endl;}
virtual ~Animal() = 0;
};
Animal::~Animal()
{
cout << "Animal虚构造函数调用!" << endl;
}
//和包含了普通纯虚函数的类一样,包含了纯虚函数的类也是一个抽象类,不能够被实例化
class Cat :public Animal {
public:
Cat(string name)
{
cout << "Cat构造函数调用" << endl;
m_Name = new string(name);
}
virtual void speak()
{
cout <<* m_Name<< "小猫在说话!" << endl;
}
~Cat()
{
cout << "cat析构函数调用" << endl;
if (this->m_Name != NULL)
{
delete m_Name;
m_Name = NULL;
}
}
public:
string* m_Name;
};
void test() {
Animal* animal = new Cat("Tom");
animal->speak();
delete animal;
}
int main()
{
test();
return 0;
}
总结:
1,析构函数或纯虚函数就是用来解决父类指针释放子类对象
2,如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3,拥有纯虚析构函数的类也属于抽象函数
七,多态案例三---电脑组装
案例描述:
电脑主要组成部件为CPU,显卡,内存条
将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如intel
厂商lenovo厂商,创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
测试时组装santaibuton
class CPU {
public:
virtual void calculate() = 0;//注意定义时一定要声明公共访问权限
};
class videoCard {
public:
virtual void dispalay() = 0;
};
class memory {
public:
virtual void storage() = 0;
};
//电脑类
class computer {
public:
//构造函数中传入三个零件指针
computer(CPU* cpu, videoCard* vc, memory* mem)//构造函数传入指针
{
m_cpu = cpu;
m_vc = vc;
m_memory = mem;
}
void dowork()//建立接口,进行多态,运行派生类的函数
{
m_cpu->calculate();
m_vc->dispalay();
m_memory->storage();
}
~computer()//析构函数清理堆区
{
if (m_cpu != NULL)
{
delete m_cpu;
m_cpu = NULL;
}
if (m_vc != NULL)
{
delete m_vc;
m_vc = NULL;
}
if (m_vc != NULL)
{
delete m_vc;
m_vc = NULL;
}
}
private:
CPU* m_cpu;//堆区定义指针维护
videoCard* m_vc;
memory* m_memory;
};
//厂商
class intelcpu :public CPU {
void calculate()
{
cout << "intel的cpu开始工作!" << endl;
}
};
class intelvideoCard :public videoCard {
void dispalay()
{
cout << "intel的显卡开始工作!" << endl;
}
};
class intelmemory :public memory {
void storage()
{
cout << "intel的内存条开始工作!" << endl;
}
};
class lenvocpu :public CPU {
void calculate()
{
cout << "lenvo的cpu开始工作!" << endl;
}
};
class lenvovideoCard :public videoCard {
void dispalay()
{
cout << "lenvo的显卡开始工作!" << endl;
}
};
class lenvomemory :public memory {
void storage()
{
cout << "lenvo的内存条开始工作!" << endl;
}
};
void test()
{
cout << "创建第一台电脑" << endl;
computer *c1=new computer(new intelcpu,new intelvideoCard,new intelmemory);//建立指针,传入派生类
c1->dowork();
cout << "________________________________" << endl;
cout << "创建第二台电脑" << endl;
computer* c2 = new computer(new intelcpu, new lenvovideoCard, new lenvomemory);
c2->dowork();
}
int main()
{
test();
return 0;
}
运行效果: