首页 > 编程 > C++ > 正文

C++中的虚函数重载

2019-11-08 02:31:10
字体:
来源:转载
供稿:网友

在一次修改代码过程中踩的坑,下来研究了一下,发现C++中虚函数重载后会产生很多有意思的情况,在这里总结了一下。

C++中有重载(overload)和重写(override)以及重定义这几个概念,1 overload:指的是相同作用域中的两个函数的函数名相同,但参数列表的个数、顺序、类型不同。而override指的是子类中重新定义的父类的虚函数。2 override:overload要求两个函数的参数列表必须不同,但是不要求这两个函数必须是虚函数。而override要求必须是虚函数且父类的虚函数必须有virtual关键字,函数的参数列表和返回值也必须相同。子类中override的虚函数的访问修饰符可以不同。3 重定义也是描述分别位于父类与子类中的同名函数的,但返回值可以不同。如果参数列表不同,这时子类中重定义的函数不论是否有virtual关键字,都会隐藏父类的同名函数。如果参数列表相同,但父类中的同名函数没有virtual关键字修饰,此时父类中的函数仍然被隐藏。

虚函数的典型用法是:

#include <iostream>using namespace std; class Base{public:    virtual void f();};void Base::f(){    cout << "Base::f()" << endl;}class Derived:public Base{public:    virtual void f();};void Derived::f(){    cout << "Derived::f()" << endl;}int main() {    Base *p1 = new Base;    Base *p2 = new Derived;    p1->f();    p2->f();        delete p1;    delete p2;    return 0;}

程序的输出是:

Base::f()Derived::f()

那么如果虚函数之间又发生了overload,会出现什么情况?我们先看最简单的情况:

#include <iostream>using namespace std; class Base{public:    virtual void f(int);};void Base::f(int a){    cout << "Base::f(int) " << a << endl;}class Derived:public Base{public:    virtual void f();};void Derived::f(){    cout << "Derived::f()" << endl;}int main() {    Base *p1 = new Base;    p1->f(1);        Base *p2 = new Derived;    p2->f();        delete p1;    delete p2;        return 0;}

编译上面的代码,会发生如下错误:

test.cpp: In function ‘int main()’:test.cpp:28:11: error: no matching function for call to ‘Base::f()’     p2->f();           ^test.cpp:10:6: note: candidate: virtual void Base::f(int) void Base::f(int a){      ^test.cpp:10:6: note:   candidate expects 1 argument, 0 PRovided

这就是因为父类中虚函数的参数列表已经发生变化,这时不论子类中重定义的函数不论是否有virtual关键字,都会隐藏父类的同名函数。这时子类中只是重定义了一个自己的函数virtual void f(),而并没有override父类中对应的虚函数。p2是一个指向Base类型的指针,根据虚函数的特性,对p2→f();的处理取决于是否override了父类的虚函数,如果没有,仍然会调用调用父类中被override的虚函数,但是现在父类中的函数已经成为了virtual void f(int),因此在执行p2→f()时会由于缺少输入参数而出现上述错误。为了证明上述论断,可以在执行p2→f()时传入参数来判断:

#include <iostream>using namespace std; class Base{public:    virtual void f(int);};void Base::f(int a){    cout << "Base::f(int) " << a << endl;}class Derived:public Base{public:    virtual void f();};void Derived::f(){    cout << "Derived::f()" << endl;}int main() {    Base *p1 = new Base;    p1->f(1);        Base *p2 = new Derived;    p2->f(2);        delete p1;    delete p2;        return 0;}

这时可以通过编译,执行结果为

Base::f(int) 1Base::f(int) 2

可以看到,子类自己定义的virtual void f()其实是父类的virtual void f(int)的一个重定义的函数,这时尽管p2实际指向了一个Derived对象,但由于没有override父类对应的虚函数,在执行 p2→f(2)时将执行父类的virtual void f(int)。也可以这样修改:

#include <iostream>using namespace std; class Base{public:    virtual void f(int);    virtual void f();};void Base::f(int a){    cout << "Base::f(int) " << a << endl;}void Base::f(){    cout << "Base::f() " << endl;}class Derived:public Base{public:    virtual void f();};void Derived::f(){    cout << "Derived::f()" << endl;}int main() {    Base *p1 = new Base;    p1->f(1);        Base *p2 = new Derived;    p2->f();        delete p1;    delete p2;        return 0;}

因为父类中定义了可被子类override的函数,所以这时执行p2→f()又会重新执行子类的virtual void f():

Base::f(int) 1Derived::f()

我们甚至还可以这样验证:

#include <iostream>using namespace std; class Base {public:    virtual void f(int);    virtual void f();};void Base::f(int a) {    cout << "Base::f(int) " << a << endl;}void Base::f() {    cout << "Base::f() " << endl;}class Derived:public Base {public:    virtual void f(float);};void Derived::f(float a) {    cout << "Derived::f(float)" << showpoint << a << endl;}int main() {    Base *p1 = new Base;    p1->f(1);        Base *p2 = new Derived;    p2->f(**2.0**);        delete p1;    delete p2;        return 0;}

这时输出仍然为

Base::f(int) 1Base::f(int) 2

这说明如果通过指向父类的指针,调用虚函数时,如果子类重定义了该虚函数(参数列表发生变化),则实际调用的仍是父类中的虚函数。上面都是通过指向父类的指针来调用虚函数的,那么如果通过指向子类的指针调用虚函数会发生什么:

#include <iostream>using namespace std; class Base {public:    virtual void f(int);    virtual void f();};void Base::f(int a) {    cout << "Base::f(int) " << a << endl;}void Base::f() {    cout << "Base::f() " << endl;}class Derived:public Base {public:    virtual void f(float);};void Derived::f(float a) {    cout << "Derived::f(float)" << showpoint << a << endl;}int main() {    Base *p1 = new Base;    p1->f(1);        Derived *p2 = new Derived;    p2->f(2.0);    p2->f(3);        delete p1;    delete p2;        return 0;}

这时输出就变为了:

Base::f(int) 1Derived::f(float)2.00000Derived::f(float)3.00000

这说明,如果通过指向子类的指针调用虚函数,并且子类重定义了父类的虚函数,这时实际调用的就将是子类中的虚函数。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选