• 重载虚函数的相关问题


    我们先看以下三个共同的术语来区分:

    ①要正常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)决定。

  • 相关阅读:
    ios实现下拉刷新,上拉加载
    ios实现瀑布流
    ios收货地址三级联动选择
    ios仿淘宝管理收货地址demo
    引用传值
    继承小结
    is操作符和as操作符
    抽象类和object类
    重写基类
    派生
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5028693.html
Copyright © 2020-2023  润新知