一文解密C++中的多态机制
作者:Aomnitrix
一.多态
1.多态的用处
众所周知C++语言的三大特性:封装、多态、继承。其中多态就是去完成某个行为,但是会根据不同的对象产生不同的状态,所以叫多态。
2.多态的实现
在继承中实现多态还需要两个条件:
1.使用基类的指针或者引用来调用虚函数
2.必须在派生类对虚函数进行重写
代码演示如下:
class A { public: virtual void func() { cout << "A::func()" << endl; } }; class B : public A { public: void func() { cout << "B::func()" << endl; } }; int main() { B b; A& a = b; a.func(); return 0; }
3.虚函数
用virtual修饰的类成员函数叫做虚函数,虽然与虚拟继承用的是同一关键字但是两者并无关联。
virtual void func(){cout << "A::func()" << endl;}
派生类的重写:
重写需要在派生类中编写与基类相同的虚函数:返回类型相同(协变除外)、函数名相同、参数相同(缺省值可不同),然后函数具体实现的不同,来完成多态。
协变
协变允许基类派生类虚函数的返回值不同,但是要求返回值是互为父/子类的指针或者引用。如下所示:
class A { public: A(int a = 1) :_a(a) {} virtual A* func(int val = 0) { cout << val<< endl; return new A; } private: int _a; }; class B : public A { public: B(int b = 1) :_b(b) {} virtual B* func(int val = 1) { cout << val<< endl; return new B; } private: int _b; }; int main() { B b; A& a = b; a.func(); return 0; }
上图中,如果返回的不是本身自己父子类的指针/引用,则可以交换顺序!需要注意的是在派生类重写基类的虚函数可以不加virtual
析构函数的重写
如果基类重写的析构函数,在派生类可以不加virtual也可以完成重写(因为编译器将析构函数的名称统一处理成destructor。)
4.override 和 final
这两个关键字都是C++11的新语法,final修饰虚函数 使得虚函数不可以重写。
override 可以在派生类函数检查是否重写的基类虚函数,如果没有就 报错。
如果不想类被继承可以采用:将构造函数设为私有、将类用final修饰为最终类
5.重载重写与重定义
重载:两个函数在同一作用域、函数名/参数相同
重写:两个函数分别在基类和派生类的作用域、函数名/参数/返回值都必须相同(协变例外)、两个函数必须是虚函数
隐藏(重定义)两个函数分别在基类和派生类的作用域、函数名相同、两个基类和派生类的同名函数不构成重写就是重定义
6.虚函数表
如果在类中定义了虚函数,那么类中就会有个虚表用来存放虚表指针。
虚函数表本质是一个存虚函数指针的指针数组
虚表中存放着虚函数,同类型对象会共用一块虚表。
子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用
有虚函数的类前4/8字节存储的是虚表的地址。
去虚表找 看是什么对象 (多态时)
虚函数重写只重写函数的实现 缺省值会使用父类的
到此这篇关于一文解密C++中的多态机制的文章就介绍到这了,更多相关C++多态机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!