重载、覆盖和隐藏的区别

重载(overload) :就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
多个重载函数在调用的时候根据函数的参数来区别不同的函数。
关键点:函数名相同,参数表不同

覆盖(override) :是指在派生类中重新对基类中的虚函数重新实现,即函数名和参数都一样,只是函数的实现体不一样。
关键词:派生类中,虚函数,函数名和参数表完全相同

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

关于这三种情况的示例代码如下

#include <iostream.h>
class Base
{
public:
  virtual void f(float x)
  {
    cout << "Base::f(float) " << x << endl;
  }

  void g(float x)
  {
    cout << "Base::g(float) " << x << endl;
  }

  void h(float x)
  {
    cout << "Base::h(float) " << x << endl;
  }
};

class Derived : public Base
{
public:
  virtual void f(float x)
  {
    cout << "Derived::f(float) " << x << endl;
  }

  void g(int x)
  {
    cout << "Derived::g(int) " << x << endl;
  }

  void h(float x)
  {
    cout << "Derived::h(float) " << x << endl;
  }
};

从以上代码能够看出:
(1)函数Derived::f(float)覆盖了Base::f(float)。
(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。

考虑代码在运行时的结果:

void main(void)
{
  Derived  d;
  Base *pb = &d;
  Derived *pd = &d;

  // Good : behavior depends solely on type of the object
  pb->f(3.14f); // Derived::f(float) 3.14
  pd->f(3.14f); // Derived::f(float) 3.14

  // Bad : behavior depends on type of the pointer
  pb->g(3.14f); // Base::g(float) 3.14
  pd->g(3.14f); // Derived::g(int) 3        (surprise!)

  // Bad : behavior depends on type of the pointer
  pb->h(3.14f); // Base::h(float) 3.14      (surprise!)
  pd->h(3.14f); // Derived::h(float) 3.14
}

在第一种调用中,函数的行为取决于指针所指向的对象。在第二第三种调用中,函数的行为取决于指针的类型。所以说,隐藏破坏了面向对象编程中多态这一特性,会使得开发人员产生混乱。

函数接口设计注意要点
在设计基类的函数接口时,不要出现既是虚函数,又对该虚函数进行了重载的情况。这样会对派生类的多态函数实现造成不便。
示例代码如下

class Base
{
  virtual foo();
  virtual foo(int n);
}

class Derived : public Base
{
  virtual foo();
}

从以上代码能够看出:

  1. Derived::foo()Base::foo() 构成了多态关系
  2. Derived::foo() 隐藏了 Base::foo(int)

所以,如果派生类希望实现 foo() 函数的多态,也就必须实现 foo(int) 的多态,否则就会出现隐藏。
如果在现有代码中已经发生了上述 Base 的情况,在不改变原有代码的情况下,可以使用在派生类中使用这样的语法 using Base::foo; ,这会将基类中所有的名为 foo 的函数引入到派生类中来。

Comments

Comments powered by Disqus