以下是一个动物说话的案例,解释了地址早绑定和地址晚绑定的区别:
#include<iostream>
using namespace std;
class animal
{
public:
void speak()
{
cout<<“动物在说话”<<endl;
}
};
class dog:class animal
{
public:
void speak()
{
cout<<“狗在说话”<<endl;
}
};
class cat:class animal
{
public:
void speak()
{
cout<<“猫在说话”<<endl;
}
};
void dospeak(animal &animal) //2、回答:这就是地址早绑定。因此在执行这个函数的时候传的是动物
{
animal.speak();
}
void test01()
{
cat cat1;//3、但是我们创建的是猫对象,我们想让猫去说话怎么办呢?
dospeak(cat); //1、思考:请问执行这个dospeak函数时会是动物在说话还是猫?答案是动物。
}
我们如何让传入什么对象就让什么对象说话呢?使用虚函数实现动态多态
这样就能根据传入对象不同再确定地址,传入猫就去找猫传入狗就去找狗。
class animal
{
public:
//加入虚函数
virtual void speak()
{
cour<<"动物在说话"<<endl;
}
}
动态多态的执行条件:
(子类函数之前加不加virtual都可以。)
那么使用多态有什么优点呢?我们利用计算器的案例来说明多态的以下优点
1. 组织结构清晰
2. 可读性强
3. 对于后期的拓展和可维护性高
/*
多态案例——计算器(实现两个操作数的加减乘除)
这里我们用普通写法和多态写法来说明多态的好处
*/
#include<iostream>
#include<string>
using namespace std;
//普通写法
class calculator
{
public:
int result(string oper)
{
if(oper=="+")
{
return num_1+num_2;
}
else if(oper=="-")
{
return num_1-num_2;
}
else if(oper=="*")
{
return num_1*num_2;
}
}
int num_1;
int num_2;
};
void test01()
{
calculator c;
c.num_1=10;
c.num_2=20;
cout<<c.num_1<<"+"<<c.num_2<<"="<<c.result("+")<<endl;
cout<<c.num_1<<"-"<<c.num_2<<"="<<c.result("-")<<endl;
cout<<c.num_1<<"*"<<c.num_2<<"="<<c.result("*")<<endl;
}
//这时候,如果我们再需要添加一个除法运算时,我们还需要去修改源代码
//我们写程序追求开闭原则,在代码完成时不去修改已经完成的代码
//这时候我们用多态去实现这个计算器就会很方便,让每一个运算规则去继承一个基类,这样再增加运算规则时就不需要动到已经写好的代码了
class basecalculator
{
public:
int num_1;
int num_2;
virtual int result(string oper) //这个函数不返回任何值,到子类中再设置
{
return 0;
}
};
class jia:public basecalculator //加法
{
public:
virtual int result(string oper) //多态使用条件:在子类中重写父类中的虚函数
{
return num_1+num_2;
}
};
class jian:public basecalculator //减法
{
public:
virtual int result(string oper) //多态使用条件:在子类中重写父类中的虚函数
{
return num_1-num_2;
}
};
class cheng:public basecalculator //乘法
{
public:
virtual int result(string oper) //多态使用条件:在子类中重写父类中的虚函数
{
return num_1*num_2;
}
};
class chu:public basecalculator //除法
{
public:
virtual int result(string oper) //多态使用条件:在子类中重写父类中的虚函数
{
return num_1/num_2;
}
};
void test02()
{
//多态的使用条件:父类的指针指向子类对象
basecalculator * h=new jia;
h->num_1=100;
h->num_2=200;
cout<<h->num_1<<"+"<<h->num_2<<"="<<h->result("+")<<endl;
//用完了记得销毁
delete h;
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
接下来讲纯虚函数——分类中的虚函数没有什么意义,也不会执行到它
所以我们把父类中的虚函数改为纯虚函数virtual void function()=0;
加了纯虚函数之后的类被称为抽象类:
抽象类有以下两个特征
- 抽象类无法实例化对象
- 抽象类的子类需要重新纯虚函数,否则子类也会变成抽象类
---------------------------------------------------------------------------------------------------------------------------------接下里讲虚析构函数和纯虚析构函数
还记得虚构函数的作用时释放掉堆区的属性,但是
纯虚析构函数和虚构函数中,必须要有一些代码的具体实现
例如在类后面补充说明 Animal::~Animal()