多态是C++面向对象的三大特性之一。
多态的分类:
静态多态:函数重载和运算符重载属于静态多态,函数名的复用;
动态多态:通过派生类和虚函数实现运行时多态。
静态多态和动态多态的区别:
静态多态的函数地址在程序编译阶段确定;
动态多态的函数地址在程序运行阶段确定。
下面是一个简单的例子:
class Fruit{
public:
// 函数前面加上virtual关键字,编译器在编译阶段就不能确定函数调用了
virtual void func(){
cout<<"这是一个水果"<<endl;
}
};
class Apple:public Fruit{
public:
void func(){
cout<<"这是一个苹果"<<endl;
}
};
class Orange:public Fruit{
public:
void func(){
cout<<"这是一个橘子"<<endl;
}
};
void visit(Fruit &fruit){
fruit.func();
}
void test01(){
Apple apple;
visit(apple);
Orange orange;
visit(orange);
}
可以看出多态的使用要满足下面的条件:
1.有继承关系;
2.子类重写父类中的虚函数;
3.使用时父类指针或者引用指向子类对象。
多态的优点:
1.代码组织结构清晰;
2.代码可读性强;
3.有利用扩展和维护。
下面是一个简单的计算器的类,可以更好的看出多态的优点。
class BaseCalculator{
public:
virtual int get_result(){
return 0;
}
public:
int m_a;
int m_b;
};
class AddCalculator:public BaseCalculator{
public:
int get_result(){
return m_a+m_b;
}
};
class SubCalculator:public BaseCalculator{
public:
int get_result(){
return m_a-m_b;
}
};
class MulCalculator:public BaseCalculator{
public:
int get_result(){
return m_a*m_b;
}
};
void test01(){
// 创建加法计算器
BaseCalculator *a=new AddCalculator;
a->m_a=5;
a->m_b=6;
cout<<a->get_result()<<endl;
// 用完要销毁
delete a;
// 创建乘法计算器
a=new MulCalculator;
a->m_a=6;
a->m_b=4;
cout<<a->get_result()<<endl;
delete a;
// 创建减法计算器
a=new SubCalculator;
a->m_a=15;
a->m_b=6;
cout<<a->get_result()<<endl;
delete a;
}
纯虚函数和抽象类:
在多态中,可以将父类中的虚函数改为纯虚函数,当类中有了纯虚函数,这个类可以被称为抽象类。
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表)=0;
抽象类的特点:
1.不能实例化对象;
2.子类必须重写抽象类中的纯虚函数,否则也是抽象类。
下面是一个小例子:
class Base{
public:
virtual void func()=0;
};
class Son:public Base{
public:
virtual void func(){
cout<<"Son中func的调用"<<endl;
}
};
void test01(){
// 因为抽象类无法实例化对象,所以先赋一个NULL
Base *base=NULL;
base=new Son;
base->func();
delete base;
}
虚析构和纯虚析构:
在使用多态时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,这是需要解决的问题。
解决方法:
将父类中的析构函数改为虚析构或者纯虚析构。
虚析构和纯虚析构的比较;
共同点;
1.可以解决父类指针释放子类对象;
2.需要有具体的实现。
区别:
如果是纯虚析构,则该类属于抽象类,无法实例化对象。
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名()=0;
类名::~类名(){}
class Base{
public:
Base(){
cout<<"Base构造函数调用"<<endl;
}
virtual void func()=0;
// 纯虚析构函数
virtual ~Base()=0;
};
Base::~Base() {
cout<<"Base析构函数调用"<<endl;
}
class Son:public Base{
public:
Son(string name){
cout<<"Son构造函数调用"<<endl;
m_name=new string(name);
}
virtual void func(){
cout<<"这是"<<*m_name<<endl;
}
~Son(){
cout<<"Son析构函数调用"<<endl;
if(this->m_name!=NULL){
delete m_name;
// 置为NULL防止出现野指针
m_name=NULL;
}
}
public:
string *m_name;
};
void test01(){
Base *base=new Son("tonny");
base->func();
delete base;
}