C++ 子类中函数的重定义

我一直只知道 C++ 子类函数对父类函数有重写操作,最近才知道了有重定义这么个概念,原因来源于类似如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Base
{
protected:
int a;
public:
virtual void seta()
{
a = 0;
}
};

class Derived : public Base
{
public:
void seta(int x)
{
a = x;
}
};
int main()
{
Derived a;
a.seta(); //error,candidate expects 1 argument, 0 provided

return 0;
}

我的本意是想调用父类中的 seta() 方法,结果却报错了。这是我当初写代码时不曾想到的。我本想这算是函数的重载,派生类中有两个方法,结果事实(程序)却说明派生类中只有一个 seta(intx)

原因

函数重载发生在相同的范围内, 也就是说在同一个作用域内, 而上面代码两个方法一个在父类, 一个在子类, 并不处于同一个作用域。 这里发生的是重定义, 基类的方法将会被隐藏。

下面给出重载,重写,重定义三者的特征。(来源: Fred^_^)

  • 函数重载(overload)
    函数重载是指在一个类中声明多个名称相同但参数列表不同的函数,这些的参数可能个数或顺序,类型不同,但是不能靠返回类型来判断。特征是:
    (1)相同的范围(在同一个作用域中);
    (2)函数名字相同;
    (3)参数不同;
    (4)virtual 关键字可有可无(注:函数重载与有无 virtual 修饰无关);
    (5)返回值可以不同;

  • 函数重写(也称为覆盖 override)
    函数重写是指子类重新定义基类的虚函数。特征是:
    (1)不在同一个作用域(分别位于派生类与基类);
    (2)函数名字相同;
    (3)参数相同;
    (4)基类函数必须有 virtual 关键字,不能有 static 。
    (5)返回值相同,否则报错;
    (6)重写函数的访问修饰符可以不同;

  • 重定义(也称隐藏)
    (1)不在同一个作用域(分别位于派生类与基类) ;
    (2)函数名字相同;
    (3)返回值可以不同;
    (4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆);
    (5)参数相同,但是基类函数没有 virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)