1.什么是多态
多态即不同的状态。在程序中体现为不同的对象去做同一行为的时候,状态、结果不同。在C++中通过基类的指针或引用调用虚函数时,不同的指针和引用会调用不同的函数。
2.多态的实现
2.1多态的条件
实现多态有两个条件:
1.虚函数重写
2.基类的指针或引用调用虚函数(指向谁调用谁的虚函数)
2.2虚函数
什么是虚函数呢,虚函数即为在类中被virtual修饰的类的非静态成员函数。如下例
class Base{
public:
virtual void func()
{
cout<< "Base::func()" <<endl;
}
};
class Derive : public Base{
public:
//在多态里称为重写/覆盖
virtual void func()
{
cout<< "Derive::func()" <<endl;
}
};
若上述Derive类中func()没有被virtual修饰与Base中的func()构成隐藏,但被修饰后再多态中被称为重写/覆盖。
实现了上示虚函数后,运行以下代码:
int main()
{
Base b; Derive d;
Base& b1 = b;
Base& b2 = d;
b1.func();
b2.func();
return 0;
}
结果如下,基类对基类对象和派生类的引用调用func()时分别调用了不同类的func()
2.3虚函数注意事项
1.虚函数需要满足三同(即函数名、参数、返回类型相同)
2.析构函数的多态,实际上编译后析构函数名字都处理为destructor(),析构函数建议设置为虚函数(涉及到资源释放等问题)
3.派生类的重写虚函数可以不加virtual,建议加上,使得层次跟清晰。
2.4C++11中的关键字
1.final 表示该函数不能被重写(放到基类中)
class Base{
public:
virtual void func()
{
cout<< "Base::func()" <<endl;
}
};
class Derive : public Base{
public:
//在多态里称为重写/覆盖
void func()final//此时再重写func()非法
{
cout<< "Derive::func()" <<endl;
}
};
2.final可修饰类(放在类名后),不可被继承,称为最终类
class Base{
public:
virtual void func()
{
cout<< "Base::func()" <<endl;
}
};
class Derive final : public Base{
public:
//在多态里称为重写/覆盖
virtual void func()
{
cout<< "Derive::func()" <<endl;
}
};
此时Derive不可被继承
2.5重载、覆盖(重写)、隐藏(重定义)的对比
重载:
1.两个函数在同一作用域
2.函数名相同,参数不同
重写(覆盖):
1.两个函数分别在基类和派生类的类域
2.函数名、参数、返回类型相同
3.基类的指针或引用调用虚函数
重定义(隐藏)
1.两个函数分别在基类和派生类的类域
2.函数名相同
3.不构成重写
3.抽象类
3.1纯虚函数
纯虚函数没有函数体,在虚函数后面加上 = 0,如下func()即为纯虚函数
class Base {
public:
virtual void func() = 0;
};
3.2抽象类概念
包含纯虚函数的类叫做抽象类(也叫接口 类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生 类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。
一般抽象类用于实现现实中抽象的事物,用于后续继承。
4.虚函数原理
实际上,当一个类中实现了虚函数,会在其对象中多存一个指针指向虚函数表,如下类
class Base {
int a;
public:
virtual void func()
{
}
};
class Derive : public Base {
public:
virtual void func()
{
}
};
上示继承中Base::func()声明为虚函数,Base中存入一个虚函数表指针,虚函数表存放函数指针指向Base::func(),在Derive重写func()之后,虚函数表更新func()函数指针指向Derive::func(),如下图
总结:
1.多态原理:(虚函数)动态编译/动态调用/运行时绑定/动态绑定;(普通成员函数)编译时绑定/静态绑定。基类指针指向不同对象,调用其虚函数表指向的函数。
5虚函数注意事项
1.虚函数的重写也叫虚函数的覆盖
2.虚函数表的本质是函数指针数组,虚函数表存在常量区
3.虚函数的函数体存在代码段
4.虚函数表指针存在对象中
5.广义多态:
静态多态,函数重载,模版。
动态多态,虚函数。