### C++中类成员函数的重写、重载和隐藏的区别
在C++中,类成员函数的重载、重写和隐藏是三个重要的概念,它们在不同的场景下有着不同的行为和用途。下面将详细解释这三个概念的区别,并给出具体的示例。
#### 1. 重载(Overload)
**定义**:在同一作用域内,当存在同名成员函数时,如果这些函数的参数列表不同(包括类型、数目或顺序),则可以被视为重载。返回值类型的不同不会影响重载的判断。
**特征**:
- **相同的范围**:在同一个类中。
- **函数名字相同**。
- **参数不同**:包括参数类型、参数个数或参数顺序的不同。
- **virtual关键字可有可无**:重载靠的是函数标识符,与`virtual`关键字无关。
**示例**:
```cpp
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
};
```
在这个例子中,`Calculator`类中有三个名为`add`的函数,它们的参数列表不同,因此它们是重载的。
#### 2. 重写(Override)
**定义**:重写是指在派生类中覆盖基类中的同名虚函数。重写要求派生类中的函数体与基类中的虚函数体相同,且参数列表和返回值与基类虚函数相同。通过使用`override`关键字确保这是对基类虚函数的重写。
**特征**:
- **不同的范围**:分别位于派生类与基类。
- **函数名字相同**。
- **参数相同**。
- **基类函数必须有virtual关键字**:子类可有可不有,没有的话编译器会自动加上`virtual`。
**示例**:
```cpp
class Base {
public:
virtual void display() {
cout << "Display from Base" << endl;
}
};
class Derived : public Base {
public:
void display() override {
cout << "Display from Derived" << endl;
}
};
```
在这个例子中,`Derived`类重写了`Base`类中的`display`虚函数。
#### 3. 隐藏(Hide)
**定义**:隐藏是指派生类中的函数在某些情况下会屏蔽基类中的同名函数。隐藏是通过将基类函数的作用域进行隐藏实现的,因此可以通过作用域解析符`::`来访问基类函数。隐藏与重载的区别在于,隐藏是基于函数参数的匹配,而重载是基于函数名和参数列表的匹配。
**特征**:
- **子类函数与基类函数同名不同参**:不论有无`virtual`,基类的所有同名函数被隐藏。
- **调用基类函数时必须显式加上“基类名::”** :如果不加的话会在编译截断报错,因为编译器会做尝试:
- 在参数数量相同时进行隐式类型转换,转换不了就会报错,而不是往基类中寻找;
- 在参数数量不同时直接报错。
**示例**:
```cpp
class Base {
public:
void show() {
cout << "Show from Base" << endl;
}
void show(int x) {
cout << "Show from Base with int" << endl;
}
};
class Derived : public Base {
public:
void show(double x) {
cout << "Show from Derived with double" << endl;
}
};
```
在这个例子中,`Derived`类中的`show(double x)`函数隐藏了`Base`类中的`show()`和`show(int x)`函数。如果通过`Derived`对象调用`show()`或`show(int x)`,编译器会报错,因为这些函数被隐藏了。可以通过`Base::show()`或`Base::show(int x)`来显式调用基类的函数。
### 总结
- **重载**:在同一作用域内,函数名相同但参数列表不同。
- **重写**:在派生类中覆盖基类的虚函数,要求函数名、参数列表相同,基类函数必须有`virtual`关键字。
- **隐藏**:派生类中的函数屏蔽了与其同名的基类函数,不论参数是否相同。
### 表格总结
| 特征 | 重载 (Overload) | 重写 (Override) | 隐藏 (Hide) |
|------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| 作用域 | 同一个类中 | 派生类与基类 | 派生类与基类 |
| 函数名 | 相同 | 相同 | 相同 |
| 参数 | 不同(类型、数目或顺序) | 相同 | 不同或相同 |
| virtual | 可有可无 | 必须有 | 无关 |
| 调用方式 | 根据参数列表确定 | 动态绑定,通过虚函数表 | 静态绑定,通过作用域解析符`::` |
| 应用场景 | 提供函数的多种使用方式 | 实现多态性 | 可能导致不易察觉的错误,需要特别注意 |
通过以上详细解释和示例,可以清晰地理解C++中类成员函数的重载、重写和隐藏的区别及其应用场景。