虚函数
一、重写发生的条件:
1.不在同一作用域。
2.函数名相等,参数相等,返回值相等。
3.基类函数必须有virtual关键字。
重写条件满足后,父类虚函数表中的父类虚函数fun()函数的地址,会被修改成子类虚函数fun()函数的地址,下一次去父类虚函数表调用的函数就是子函数的fun(),重写是构成多态最重要的一个条件。
重写的过程看起来和隐藏很相似,其实不然,隐藏之后还是可以通过限定作用域找到被隐藏的元素,但是重写是完完全全在虚函数表里面给把它写掉了,再也找不到被重写的那个元素了。
二、继承体系同名成员函数的关系
1、重载:在同一作用域;函数名相同,参数不同;返回值可以不同
2、重写(覆盖):不在同一作用域(分别在基类和派生类);函数名相同,参数相同,返回值相同(协变例外);基类函数必须有virtual关键字;访问修饰符可以不同。
3、重定义(隐藏):在不同作用域中(分别在基类和派生类中);函数名相同;在基类和派生类中只要不构成重写就是重定义
三、总结
1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同(协变除外)。
2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
3、只有类的成员函数才能定义为虚函数。
4、静态成员函数不能定义成虚函数,
5、如果在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual。
6、不要在构造函数和析构函数里面调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会发生未定义的行为。
7、最好把基类的析构函数声明为虚函数。(why?析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里是因为编译器做了特殊处理。)
8、构造函数不能为虚函数,虽然可以将operator=定义为虚函数,但是最好不要将operator=定义为虚函数,因为使用时容易引起混淆。
解释:1.为什么静态成员函数不能定义为虚函数?
因为静态成员函数是一个大家共享的资源,但是静态成员函数没有this指针,而且虚函数变只有对象才能调到,但是静态成员函数不需要对象就可以调用,所以这里是有冲突的。
2、为什么不要在构造函数和析构函数里面调用函数?
构造函数当中不适合用虚函数的原因是:在构造对象的过程中,还没有为“虚函数表”分配内存。所以,这个调用也是违背先实例化后调用的准则;