虚函数重载的相关问题

我们首先对下面三个常见的术语进行区分:

①对函数f()进行重载(overload)是表示,在相同的作用域中定义另一个相同的名字(f)的函数,并且这个函数与f()有着不同的参数个数和参数类型。当程序调用函数f()时,编译器将会根据实际提供的参数来选择最匹配的函数。

②对虚函数f()进行覆盖(override)是表示,在派生类中定义一个相同的名字(f)的函数,并且这个函数的参数个数和参数类型与f()是相同的。

③对外层作用域(基类、外部类或者名字空间)中的函数f()进行隐藏(hide)是表示在内层作用域(派生类、嵌套类或者嵌套名字空间)中定义另一个相同名字(f)的函数,这将隐藏外层作用域中相同名字的函数。

下面看一个例子:

class Base

{

public:

virtual void f(int);

virtual void f(double);

virtual void g(int i = 10);

};

void Base::f(int)

{

cout << "Base::f(int)" << endl;

}

void Base::f(double)

{

cout << "Base::f(double)" << endl;

}

void Base::g(int i)

{

cout << i << endl;

}

class Derived:public Base

{

public:

void f(complex<double>);

void g(int i = 20);

};

void Derived::f(complex<double> a)

{

cout << "Derived::f(complex)" << endl;

}

void Derived::g(int i)

{

cout << "Derived::g()" << i << endl;

}

int main()

{

Base b;

Derived d;

Base* pb = new Derived;

b.f(1.0);

d.f(1.0);

pb->f(1.0);

b.g();

d.g();

pb->g();

delete pb;

return 0;

}

①“delete pb;”是不安全的

我们通常应该将基类的析构函数定义为虚函数。在上面的代码中,我们是通过指向基类的指针来删除派生类的对象,而在基类中并没有定义虚析构函数,那么这就会产生问题,上面代码将调用错误的析构函数。

②Derived::f不是重载函数

在Derived类中并不是对Base::f进行重载,而是隐藏了这个函数。这个区别是很重要的,因为它意味着在Derived的作用域中,Base::f(int)和Base::f(double)将是不可见的。如果要将Base::f这个名字引入到Derived的作用域中,正确地方法是使用using声明语句------“using Base::f"。

③我们永远都不要去改变所覆盖的基类函数中的默认参数值

函数Derived::g覆盖了Base::g,但却改变了默认参数值void g(int i = 20);

下面分析上面的程序的输出结果:

b.f(1.0);调用Base::f(double),这与程序员所期望的是一致的。

d.f(1.0);将调用Derived::f(complex<double>).因为Base::f(int)和Base::f(double)被Derived::f(complex<double>)隐藏了。我们可能希望这行代码会去调用Base::f(double),但在这种情况下是不会的,而且编译器甚至不会报错,因为幸运的是,complex<double>能够提供从double来的隐式转换,因此编译器会将这个调用解释为Derived::f(complex<double>(1.0)).

pb->f(1.0);虽然指针Base  * pb指向的是一个Derived对象,但上面这行代码调用的却是Base::f(double),这是因为重载解析只是作用于静态类型(这里是Base),而不是动态类型(这里是Derived)。同理,函数调用”pb->f(complex<double>(1.0))“将无法通过编译,这是因为在Base的接口中没有符合要求的函数。

b.g();将输出”10“,调用了Base::g(int).

d.g();将输出”Derived::g()20",因为这只是调用了Derived::g(int),而这个函数的默认参数值是20.

pb->g();这段代码将输出“Derived::g()10"。我们要记住的是,与函数重载一样,默认参数是来自于对象的静态类型(这里是Base),因此获得的默认值是10.然而,由于这个函数是虚函数,因此实际调用的函数将由对象的动态类型(这里是Derived)来决定。

时间: 2024-08-03 14:22:11

虚函数重载的相关问题的相关文章

C++ 11 学习3:显示虚函数重载(override)

5.显示虚函数重载 在 C++ 里,在子类中容易意外的重载虚函数.举例来说: struct Base { virtual void some_func(); }; struct Derived : Base { void some_func(); }; Derived::some_func 的真实意图为何? 程序员真的试图重载该虚函数,或这只是意外? 这也可能是 base 的维护者在其中加入了一个与Derived::some_func 同名且拥有相同参数的虚函数. 另一个可能的状况是,当基类中的

自动设置ip bat文件 虚函数重载

实现软件启动的时候就自动修改ip地址,可以自动调用 重载项目ForcePlate.cpp中的InitInstance()函数,并在该初始化函数中加 ShellExecute(NULL, _T("open"), _T("1.bat"),NULL, m_strEXEPath, SW_SHOW); 1.bat文件:(修改ip) netsh int ip set addr name="本地连接" source=static addr=192.168.2.

特别优秀的虚函数讲解博客地址

http://blog.csdn.net/haoel/article/details/1948051/ C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么

C++中虚函数

本文为博主学习虚函数时,结合网上博客和相关书籍所写.主要分为两部分:虚函数的定义要遵循的规则,虚函数表. 一.虚函数的定义要遵循的规则 1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的. 解读:派生类中根据需要对虚函数进行重定义是,格式要求有三点: (1)与基类的虚函数有相同的参数个数: (2)与基类的虚函数有相同的参数类型: (3)与基类的虚函数有相同的返回类型:或者与基类虚函数的相同,或者都返回

C++ 虚函数表解析(比较清楚,还可打印虚函数地址)

C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以

C++虚函数运行机制

C++ 虚函数表解析 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的书籍.在这篇文章中,我只想从虚函

【转】C++虚函数解析

本文转自陈皓大叔(左耳朵耗子)的博客www.coolshell.com. 文章是很久之前所写,去年还在写C++时有幸拜读,现在想起来还是相当有价值一转的,如果有一定C++基础(特别是读过<深度探索C++对象模型>)应该可以比较无痛地理解这篇文章.另外十分打心底敬佩那些肯花大量时间和心血写这些高质量文章的前辈. ========================================================================================== C+

C++ 虚函数经典深入解析

C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的书籍.在这篇文章中,我只想从虚函数的实现机制上面为大家 一个清晰的剖析

C++虚函数实现原理详解

前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的书籍.在这篇文章中,我只想从虚函数的实现机制上面为大家