zoukankan      html  css  js  c++  java
  • 重载(overload)、覆盖(override)和隐藏(hide)

    写正题之前,先给出几个关键字的中英文对照,重载(overload),覆盖(override),隐藏(hide)。在早期的C++书籍中,可能翻译的人不熟悉专业用语(也不能怪他们,他们不是搞计算机编程的,他们是英语专业的),常常把重载(overload)和覆盖(override)搞错!

      我们先来看一些代码及其编译结果。

      实例一:
      
      #include "stdafx.h"
      #include <iostream.h>

      class CB
      {
      public:
        void f(int)
        {
           cout << "CB::f(int)" << endl;
         }

      };


      class CD : public CB
      {
      public:
         void f(int,int)
        {
          cout << "CD::f(int,int)" << endl;
        }

        void test()
        {
         f(1);
        }
      };

     int main(int argc, char* argv[])
     {
        return 0;
     }
    编译了一下
    error C2660: 'f' : function does not take 1 parameters


    结论:在类CD这个域中,没有f(int)这样的函数,基类中的void f(int)被隐藏

      如果把派生CD中成员函数void f(int,int)的声明改成和基类中一样,即f(int),基类中的void f(int)还是一样被覆盖,此时编译不会出错,在函数中test调用的是CD中的f(int) 

      所以,在基类中的某些函数,如果没有virtral关键字,函数名是f(参数是什么我们不管),那么如果在派生类CD中也声明了某个f成员函数,那么在类CD域中,基类中所有的那些f都被隐藏。
      如果你比较心急,想知道什么是隐藏,看文章最后的简单说明,不过我建议你还是一步一步看下去。

      我们刚才说的是没有virtual的情况,如果有virtual的情况呢??
      实例二:

    #include "stdafx.h"
    #include <iostream.h>

    class CB
    {
    public:
      virtual void f(int)
      {
        cout << "CB::f(int)" << endl;
      }

    };


    class CD : public CB
    {
    public:
       void f(int)
      {
        cout << "CD::f(int)" << endl;
       }

    };

    int main(int argc, char* argv[])
    {
     return 0;
    }

      这么写当然是没问题了,在这里我不多费口舌了,这是很简单的,多态,虚函数,然后什么指向基类的指针指向派生类对象阿,通过引用调用虚函数阿什么的,属性多的很咯,什么??你不明白??随便找本C++的书,对会讲多态和虚函数机制的哦!!
      这种情况我们叫覆盖(override)!覆盖指的是派生类的虚拟函数覆盖了基类的同名且参数相同的函数!
      在这里,我要强调的是,这种覆盖,要满足两个条件
     (a)有virtual关键字,在基类中函数声明的时候加上就可以了
     (b)基类CB中的函数和派生类CD中的函数要一模一样,什么叫一模一样,函数名,参数,返回类型三个条件
      有人可能会对(b)中的说法质疑,说返回类型也要一样??
      是,覆盖的话必须一样,我试了试,如果在基类中,把f的声明改成virtual int f(int),编译出错了
      error C2555: 'CD::f' : overriding virtual function differs from 'CB::f' only by return type or calling convention
      所以,覆盖的话,必须要满足上述的(a)(b)条件

      那么如果基类CB中的函数f有关键字virtual ,但是参数和派生类CD中的函数f参数不一样呢,
    实例三:
    #include "stdafx.h"
    #include <iostream.h>

    class CB
    {
     public:
       virtual void f(int)
       {
         cout << "CB::f(int)" << endl;
       }

    }
    ;


    class CD : public CB
    {
    public:
       void f(int,int)
      {
        cout << "CD::f(int,int)" << endl;
      }

      void test()
      {
         f(1);
      }
    }
    ;

    int main(int argc, char* argv[])
    {
    return 0;
    }

    编译出错了,
    error C2660: 'f' : function does not take 1 parameters
      咦??好面熟的错??对,和实例一中的情况一样哦,结论也是基类中的函数被隐藏了。

      通过上面三个例子,得出一个简单的结论
    如果基类中的函数和派生类中的两个名字一样的函数f
    满足下面的两个条件
    (a)在基类中函数声明的时候有virtual关键字
    (b)基类CB中的函数和派生类CD中的函数一模一样,函数名,参数,返回类型都一样。
    那么这就是叫做覆盖(override),这也就是虚函数,多态的性质

    那么其他的情况呢??只要名字一样,不满足上面覆盖的条件,就是隐藏了。

    下面我要讲最关键的地方了,好多人认为,基类CB中的f(int)会继承下来和CD中的f(int,int)在派生类CD中构成重载,就像实例一中想像的那样。
      对吗?我们先看重载的定义
      重载(overload):
      必须在一个域中,函数名称相同但是函数参数不同,重载的作用就是同一个函数有不同的行为,因此不是在一个域中的函数是无法构成重载的,这个是重载的重要特征
      必须在一个域中,而继承明显是在两个类中了哦,所以上面的想法是不成立的,我们测试的结构也是这样,派生类中的f(int,int)把基类中的f(int)隐藏了
      所以,相同的函数名的函数,在基类和派生类中的关系只能是覆盖或者隐藏。

      在文章中,我把重载和覆盖的定义都给了出来了,但是一直没有给隐藏的定义,在最后,我把他给出来,这段话是网上google来的,比较长,你可以简单的理解成,在派生类域中,看不到基类中的那个同名函数了,或者说,是并没有继承下来给你用,呵呵,如实例一 那样。
      

    隐藏(hide):
    指的是派生类的成员函数隐藏了基类函数的成员函数.隐藏一词可以这么理解:在调用一个类的成员函数的时候,编译器会沿着类的继承链逐级的向上查找函数的定义,如果找到了那么就停止查找了,所以如果一个派生类和一个基类都有同一个同名(暂且不论参数是否相同)的函数,而编译器最终选择了在派生类中的函数,那么我们就说这个派生类的成员函数"隐藏"了基类的成员函数,也就是说它阻止了编译器继续向上查找函数的定义

  • 相关阅读:
    ExtJS小技巧
    Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
    NPM 私服
    IDEA 不编译java以外的文件
    SQL 引号中的问号在PrepareStatement 中不被看作是占位符
    Chrome 浏览器自动填表呈现淡黄色解决
    批量删除Maven 仓库未下载成功.lastupdate 的文件
    Oracle 11g 监听很慢,由于监听日志文件太大引起的问题(Windows 下)
    Hibernate 自动更新表出错 建表或添加列,提示标识符无效
    Hibernate 自动更新表出错 More than one table found in namespace
  • 原文地址:https://www.cnblogs.com/freesblog/p/4004884.html
Copyright © 2011-2022 走看看