码迷,mamicode.com
首页 > 其他好文 > 详细

虚函数重载的相关问题

时间:2014-07-21 11:26:05      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:编译器   函数重载   基类   派生类   静态类型   

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

①对函数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)来决定。

虚函数重载的相关问题

标签:编译器   函数重载   基类   派生类   静态类型   

原文地址:http://blog.csdn.net/fayery/article/details/37997367

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!