主要内容
好处
C++11
提供override
关键字用于保障虚函数重载的正确性.虚函数重载
和父类的虚函数声明一毛一样.
如何一样
虚函数才能重载.
函数名一样.(析构除外).
入参一样.
函数修饰一样.
返回值和异常处理兼容.
非虚函数
案例
#include <iostream> #include <memory> class A { public: void show(int a){ std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: void show(int a) { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); a->show(1); }
输出
show : 6 [Finished in 651ms]
函数名一致
略
析构
#include <iostream> #include <memory> class A { public: virtual ~A() { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: ~B() { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); delete a; }
输出
~B : 13 ~A : 6 [Finished in 502ms]
显式调用
#include <iostream> #include <memory> class A { public: virtual ~A() { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: ~B() { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); a->~A(); }
输出
~B : 13 ~A : 6 [Finished in 506ms]
入参不一致
案例
#include <iostream> #include <memory> class A { public: virtual void show(int a){ std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: virtual void show(bool a) { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); a->show(1); }
int
和bool
参数不一样,是两个函数.
1
的匹配show(int)
的准确度更高.show : 6 [Finished in 477ms]
小结
函数都不是一个函数,更别说重载了.
不是一个函数,就相当于新声明了一个虚函数.
修饰不一致
案例
#include <iostream> #include <memory> class A { public: virtual void show(int a) const { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: virtual void show(int a) { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); a->show(1); }
修饰不一致,
B
的实现没有const
.所以是两个函数.show : 6 [Finished in 808ms]
两个函数则调用当前类型匹配度最高的.
小结
修饰不一样,函数名也不再一样.所以重载的也就不一样.
override
解决的问题
核心功能
检测父类中是否却有如此声明的虚函数.
即编译器帮忙检测是否正确的继承了函数.而不是说子类重载了个寂寞.
C++11
对函数进行修饰,可以根据不同的上下文进行不同的操作.
能够更加精确的控制.和更高的利用率.
但是带来了重载的麻烦。
改动
如果基类进行了相关的改动.
那么子类声明了
override
的都会在编译阶段就发现了改动的问题.
override
生效
尽在函数末尾生效,函数名或变量不会检测,或者是相关语义.
final
禁止重载
表示当前类的某个虚函数不能被重载.
案例
#include <iostream> #include <memory> class A { public: virtual void show(int a) const final { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; class B:public A { public: virtual void show(int a) const override { std::cout << __FUNCTION__ << " : " << __LINE__ << std::endl; } }; int main() { A *a = new B(); a->show(1); }
B
想重载父类的,但是父类不允许重载. 则编译报错.D:\codes\cfile\Test\test.cpp:12:18: error: virtual function 'virtual void B::show(int) const' overriding final function virtual void show(int a) const override { ^~~~ D:\codes\cfile\Test\test.cpp:5:18: note: overridden function is 'virtual void A::show(int) const' virtual void show(int a) const final { ^~~~ [Finished in 371ms]
一般适用于叶子节点.
符号修饰的函数场景
说明
- 对应类型调用对应的函数.
- 比如左值右值就有天差地别.
[]
一般都是返回左值.
但是当一个右值调用的时候也返回左值,就会出现引用悬空.
即可能出现
bug
.语义
&
是一个普通变量.
&&
是一个不能取地址的,没有名字不能被引用的.虽然入参是右值,但是在调用函数内部,其变成了左值,因为可以放在等号左边,也可以取地址. 只是一个
&&
类型的变量而已.消亡
- 语义上会立即释放.可以处于节约自由操作其资源.
返回值和异常兼容
略,还是需要严格一致. 没有看懂.
总结
override
表明当前函数必然是重载父类虚函数,而不是自定义声明.可以避免重载错误,和上层改动,下游的继承子类不清楚情况.