### C++ 中重写、重载与重定义的区别
在 C++ 编程语言中,重写(Override)、重载(Overload)以及重定义(Redefine 或 Hide)是面向对象编程中非常重要的概念。这三个概念虽然在字面上相似,但它们在实际应用中的含义和作用却大相径庭。接下来,我们将详细解析这三个概念的特点及其应用场景。
#### 1. 重载 (Overload)
重载是指在同一作用域内,允许定义多个同名但参数列表不同的函数或方法。重载只发生在类的内部,它依赖于参数列表的不同来进行区分,而不会考虑返回类型。这意味着即使两个函数的返回类型不同,只要参数列表相同,也无法通过重载来区分它们。成员函数重载的具体特征如下:
- **相同的范围**:这些函数必须处于同一个类中。
- **函数名字相同**:所有被重载的函数具有相同的名字。
- **参数类型、个数不同**:这是区分不同重载函数的关键。
- **virtual 关键字可有可无**:重载函数并不需要 virtual 关键字。
#### 2. 重写 (Override)
重写也称为覆盖,指的是派生类函数覆盖基类函数。这种现象通常发生在继承体系中,即子类重新定义了父类中具有相同名称和参数列表的虚函数。这使得子类能够提供不同于父类的行为,同时保持接口的一致性。重写的主要特点包括:
- **不同的范围**:重写的函数分别位于基类和派生类中。
- **函数的名字相同**:基类和派生类中的函数必须具有相同的名字。
- **参数相同**:重写的函数必须具有相同的参数列表。
- **基类函数必须有 virtual 关键字**:为了实现多态,基类中的函数需要声明为 virtual。
重写时还需要注意以下几点:
- **不能重写 static 函数**:被重写的函数不能是 static 类型的。
- **重写函数必须与基类函数具有相同的类型、名称和参数列表**:这是重写的基本条件之一。
- **重写函数的访问修饰符可以不同**:例如,即使基类中的虚函数是 private 的,派生类也可以将其重写为 public 或 protected。
#### 3. 重定义 (Redefine 或 Hide)
重定义,有时也被称为隐藏,指的是派生类重新定义了与基类中同名但非虚的函数。这会导致基类中的同名函数在派生类的作用域中不可见。重定义的主要规则如下:
- **如果派生类的函数与基类的函数同名但参数不同**:无论是否使用 virtual 关键字,基类中的函数都会被隐藏。
- **如果派生类的函数与基类的函数同名且参数相同**:但基类中的函数没有使用 virtual 关键字,则基类中的函数会被隐藏。
#### 示例代码分析
下面通过一个简单的示例代码来进一步说明这三个概念的应用。
```cpp
class Parent {
public:
void abc(int a) { printf("parent::void abc(int a)\n"); }
void abc() { printf("parentabc\n"); }
// virtual void func()
void func() { cout << "Parent::void func()" << endl; }
virtual void func(int i, int j) { cout << "Parent::void func(int i, int j)" << endl; }
virtual void func(int i, int j, int k) { cout << "Parent::void func(int i, int j, int k)" << endl; }
};
class Child : public Parent {
public:
// 重定义
void abc() { printf("childabc\n"); }
void func(int i, int j) { cout << "Child::void func(int i, int j)" << endl; }
void func(int i, int j, int k) { cout << "Child::void func(int i, int j, int k)" << endl; }
};
int main() {
Child c1;
c1.abc(); // 调用的是 Child 类中的 abc()
// c1.abc(10); // 无法编译,因为 Child 类中没有 abc(int) 的重载版本
// c1.func(); // 无法编译,因为 Child 类中已经重定义了 func(),从而隐藏了 Parent 类中的 func()
c1.Parent::func(); // 显式地调用了 Parent 类中的 func()
return 0;
}
```
在这个例子中,我们可以看到 `Child` 类中的 `abc()` 方法隐藏了 `Parent` 类中的 `abc()` 方法。此外,`Child` 类还提供了 `func(int, int)` 和 `func(int, int, int)` 的重载版本,但并没有重写 `Parent` 类中的 `func()` 方法,因此后者仍然可以被访问(通过使用作用域解析运算符 `Parent::func()`)。通过这个例子,我们可以更清晰地理解重载、重写和重定义之间的区别。