一文彻底解决C++中的重载、重写和隐藏操作

简介: 一文彻底解决C++中的重载、重写和隐藏操作

一文彻底解决C++中的重载、重写和隐藏操作

往期C++系列相关内容:

C++ 类中静态成员和静态成员函数的继承覆盖

C++中的.和->

网络相关内容:

select、poll、epoll、多线程实现并发请求处理

epoll-reactor模型原理代码解析

Http解析实现/服务器Get请求的实现

epoll的水平触发LT以及边沿触发ET的原理及使用及优缺点

UDP的可靠传输/KCP是怎样练成的

怎么回答TCP的三次握手问题


一文彻底解决C++中的重载、重写和隐藏操作,本文基本将所有的重载、重写、隐藏出现的情况罗列了出来,如果有纰漏或者错误还请指正。

直接上菜!!!!!!!!!!!!!(此处看不懂请直接跳到”重载“内容。)

假设两个函数在同个一类中,函数名相同,则可能会有这些情况产生。

表中,返回值相同的意思是,两个同名函数的返回值的类型相同;虚函数(Y)的意思是假设被重载的函数是虚函数,虚函数(N)表示不是虚函数;输入参数(Y)表示输入参数的形式相同(参数个数,参数类型都相同),输入参数(N)表示输入参数的类型不同。

返回值相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 编译出错
输入参数(N) 重载 重载

表中,返回值不相同的意思是,两个同名函数的返回值的类型不相同;

返回值不相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 编译出错
输入参数(N) 重载 重载

假设两个函数在不同类中,函数名相同,则可能会有这些情况产生。

表中,返回值相同的意思是,两个同名函数的返回值的类型相同;虚函数(Y)的意思是假设被基类的函数是虚函数,虚函数(N)表示不是虚函数;输入参数(Y)表示输入参数的形式相同(参数个数,参数类型都相同),输入参数(N)表示输入参数的类型不同。

返回值相同 虚函数(Y) 虚函数(N)
输入参数(Y) 重写 隐藏
输入参数(N) 隐藏 隐藏
返回值不相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 隐藏
输入参数(N) 隐藏 隐藏

重载(overload)

重载是指在同一范围定义中的同名成员函数才存在重载关系。

同一范围:例如重载关系的两个函数都是全局函数或者都在一个类中。

这个“同一范围”的限制条件很重要!!!!!!!! 假如在不同类中/父子类中的函数都不存在重载情况

特点:函数名相同,参数类型和数目有所不同。

举个例子:

#include <iostream>
using namespace std;
class Solutuion {
public:
    void Max(int a, int b)//输入参数都是int类型
    {
        cout << "Max 1" << endl;
    }
    void Max(char a, int b)//与上面的函数函数名相同,但第一个输入参数是char类型。发生重载
    {
        cout << "Max 2" << endl;
    }
};
int main() {
    Solutuion test;
    test.Max(1,2);
    test.Max('a',2);
    return 0;
}

结果:

重载中的注意事项

易错注意点:

注意1:参数个数和类型均相同,返回值不同的相同函数名的函数是错误的,不能重载。(编译错误)

例如:

class Solutuion {
public:
    void Max(int a, int b)
    {
        cout << "Max 1" << endl;
    }
    int Max(int a, int b) //和上面的函数名以及输入参数都相同。仅仅返回类型不同。发生编译错误,无法编译通过
    {
        cout << "Max 2" << endl;
        return 0;
    }
};

注意2:重载功能与函数成员是否是虚函数无关。

class Solutuion {
public:
    virtual void Max(int a, int b)
    {
        cout << "Max 1" << endl;
    }
    void Max(char a, int b)//虽然上面是虚函数,但这也是重载
    {
        cout << "Max 2" << endl;
    }
};

其实可以理解成虚函数(virtual)只在不同范围内如父类和子类)起作用。在上述程序中,函数都处于一个类,判断两个函数的关系可以不用看是否是虚函数。

比如下面这种错误的例子:

class Solutuion {
public:
    virtual void Max(int a, int b)//虚函数
    {
        cout << "Max 1" << endl;
    }
    void Max(int a, int b)//不是虚函数,但函数名,输入参数都一样。编译错误:重复声明类成员函数
    {
        cout << "Max 2" << endl;
    }
};

重写(override)

重写指的是在派生类中覆盖基类中的同名函数,重写就是重写函数体

特点

  1. 要求基类函数必须是虚函数
  2. 与基类的虚函数有相同的参数个数
  3. 与基类的虚函数有相同的参数类型
  4. 与基类的虚函数有相同的返回值类型

举个例子:

#include <iostream>
using namespace std;
class A {
public:
    virtual void Max(int a, int b)//输入参数都是int类型
    {
        cout << "Max 1" << endl;
    }
};
class B : public A{//B继承了A类
public:
    void Max(int a, int b)//输入参数都是int类型, 父类是虚函数,发生了重写
    {
        cout << "Max 2" << endl;
    }
};
int main() {
    A Atest;
    Atest.Max(1,2);
    B Btest;
    Btest.Max(1,2);
    return 0;
}

结果:

重写与重载的区别:

重写是父类和子类之间的垂直关系(不同类),重载是不同函数之间的水平关系(同一范围)

重写要求参数列表相同返回值相同;重载则要求参数列表不同返回值不要求(可相同可不同)

重写关系中,调用方法根据对象类型决定;重载根据调用时实参表与形参表的对应关系来选择函数体

重写中的注意事项

注意一点:返回值必须相同。(有个协变的概念,返回的类型“小于”父类也可以,这种情况本文不研究)

例如下面错误的例子:

class A {
public:
    virtual void Max(int a, int b)//输入参数都是int类型
    {
        cout << "Max 1" << endl;
    }
};
class B : public A{//B继承了A类
public:
    int Max(int a, int b)//输入参数都是int类型, 父类是虚函数,但是返回类型与父类不同,编译出错
    {
        cout << "Max 2" << endl;
        return 0;
    }
};

隐藏(hide)

函数的隐藏有两种形式

隐藏1:位于父类与子类中的同名函数,返回值可以不同。两个函数参数相同,但是基类函数不是虚函数

这个隐藏形式和重写的区别在于基类(父类)函数是否是虚函数。

举个例子:

#include <iostream>
using namespace std;
class A {
public:
    void Max(int a, int b)//输入参数都是int类型
    {
        cout << "Max 1" << endl;
    }
};
class B : public A{//B继承了A类
public:
    void Max(int a, int b)//输入参数都是int类型, 父类不是虚函数。隐藏父类的Max函数
    {
        cout << "Max 2" << endl;
    }
};
int main() {
    A Atest;
    Atest.Max(1,2);
    B Btest;
    Btest.Max(1,2);
    return 0;
}

结果:

隐藏2:位于父类与子类中的同名函数,返回值可以不同。如果参数列表不同无论基类函数是不是虚函数。子类中的函数都会隐藏父类的同名函数。

这个隐藏形式和重载的区别在于两个函数不在同一个类中。

举个例子:

#include <iostream>
using namespace std;
class A {
public:
    void Max(int a, int b)//输入参数都是int类型
    {
        cout << "Max 1" << endl;
    }
};
class B : public A{//B继承了A类
public:
    void Max(char a, int b)//输入参数类型不同。会隐藏父类的Max函数
    {
        cout << "Max 2" << endl;
    }
};
int main() {
    A Atest;
    Atest.Max(1,2);
    B Btest;
    Btest.Max(1,2);
    return 0;
}

结果:

隐藏中的注意事项

注意:假如基类的函数被隐藏掉,指向子类的对象是无法调用被隐藏的函数。编译时就会出错。

例如:

#include <iostream>
using namespace std;
class A {
public: 
    void Max(int a, int b){}
};
class B : public A{
public: 
    int Max(char a){
        return 0;
    }
};
int main() {
    A Atest;
    Atest.Max(1,2);
    B Btest;
    Btest.Max('a');//正确调用
    Btest.Max(1,2);//编译出错,虽然基类中的函数符合它的传入参数形式,但是基类中符合它类型的函数已经被隐藏了
    return 0;
}

总结

到此为止对于重载、重写、隐藏的解释基本完成了,但还有一些情况没说明到。下面从排列组合所有会发生的情况总结一下。

上面的示例主要涉及到这几个不定项:

返回值类型是否相同,父类中的同名函数是否虚函数,输入参数是否相同

由于重载只能在同一范围内,而重写和隐藏在不同的类中,因此将重载独立出来分析。采用函数在同一个类中来总结所有情况

同一个类中

(同一个类就不涉及父类虚函数的情况了,指的是被重载的函数是虚函数的情况)

//返回值类型相同的情况
// 返回值类型相同  是虚函数  输入参数不同
    virtual void Max(int a, int b) {}   
    void Max(char a, int b){} //重载
// 返回值类型相同  不是虚函数  输入参数不同
    void Max(int a, int b) {}   
    void Max(char a, int b){} //重载
// 返回值类型相同  是虚函数  输入参数相同
    virtual void Max(int a, int b) {}   
    void Max(int a, int b){}  //编译错误,重声明
// 返回值类型相同  不是虚函数  输入参数相同
    void Max(int a, int b) {}   
    void Max(int a, int b){}  //编译错误,重声明
//返回值类型不相同的情况
// 返回值类型不相同  是虚函数  输入参数不同
    virtual void Max(int a, int b) {}   
    int Max(char a, int b){}  //重载
// 返回值类型不相同  不是虚函数  输入参数不同
    void Max(int a, int b) {}   
    int Max(char a, int b){}  //重载
// 返回值类型不相同  不是虚函数  输入参数相同
    void Max(int a, int b) {}   
    int Max(int a, int b){} //编译错误
// 返回值类型不相同  是虚函数  输入参数相同
    virtual void Max(int a, int b) {}   
    int Max(int a, int b){} //编译错误

首尾呼应,表格展示

返回值相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 编译出错
输入参数(N) 重载 重载
返回值不相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 编译出错
输入参数(N) 重载 重载

不同类中

不同类中会发生重写或隐藏的情况,不会发生重载

//返回值类型相同的情况
// 返回值类型相同  是虚函数  输入参数不同
class A {public: virtual void Max(int a, int b){}};//为了节省空间,就没按照编程规范写了,勿怪
class B : public A{public: void Max(char a, int b){}};//隐藏
// 返回值类型相同  不是虚函数  输入参数不同
class A {public: void Max(int a, int b){}};
class B : public A{public: void Max(char a, int b){}};//隐藏
// 返回值类型相同  是虚函数  输入参数相同
class A {public: virtual void Max(int a, int b){}};
class B : public A{public: void Max(int a, int b){}};//重写
// 返回值类型相同  不是虚函数  输入参数相同
class A {public: void Max(int a, int b){}};
class B : public A{public: void Max(int a, int b){}};//隐藏
//返回值类型不相同的情况
// 返回值类型不相同  是虚函数  输入参数不同
class A {public: virtual void Max(int a, int b){}};//
class B : public A{public: int Max(char a, int b){return 0;}};//隐藏
// 返回值类型不相同  不是虚函数  输入参数不同
class A {public: void Max(int a, int b){}};
class B : public A{public: int Max(char a, int b){return 0;}};//隐藏
// 返回值类型不相同  是虚函数  输入参数相同
class A {public: virtual void Max(int a, int b){}};
class B : public A{public: int Max(int a, int b){return 0;}};//编译出错
// 返回值类型不相同  不是虚函数  输入参数相同
class A {public: void Max(int a, int b){}};
class B : public A{public: int Max(int a, int b){return 0;}};//隐藏
返回值相同 虚函数(Y) 虚函数(N)
输入参数(Y) 重写 隐藏
输入参数(N) 隐藏 隐藏
返回值不相同 虚函数(Y) 虚函数(N)
输入参数(Y) 编译出错 隐藏
输入参数(N) 隐藏 隐藏

希望本文可以让你系统的了解重载、重写和隐藏的特点和各自的区别。如果有错误内容,还请指出。

希望每一次发奋努力的背后,必有加倍的赏赐赋予。

目录
相关文章
|
1月前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
29 1
|
5天前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
12天前
|
C++
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
13 0
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
|
14天前
|
C++ iOS开发 开发者
C++一分钟之-文件输入输出(I/O)操作
【6月更文挑战第24天】C++的文件I/O涉及`ifstream`, `ofstream`和`fstream`类,用于读写操作。常见问题包括未检查文件打开状态、忘记关闭文件、写入模式覆盖文件及字符编码不匹配。避免这些问题的方法有:检查`is_open()`、显式关闭文件或使用RAII、选择适当打开模式(如追加`ios::app`)以及处理字符编码。示例代码展示了读文件和追加写入文件的实践。理解这些要点能帮助编写更健壮的代码。
25 2
|
22天前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
41 10
|
17天前
|
安全 程序员 C++
C++一分钟之-重载运算符
【6月更文挑战第21天】C++的运算符重载让程序员能为自定义类型定制运算符行为,增强代码表达力。但要注意清晰性、优先级和返回类型。遵循运算符原有意义,充分测试,并用注释解释非直观设计。示例展示了如何为复数类重载`+`运算符。避免重载内置类型,注意结合性,且慎用隐式转换。重载应提升可读性而非复杂化代码。
18 2
|
12天前
|
算法 C++ 容器
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
26 0
|
12天前
|
C++
C++函数的默认参数、占位符、重载
C++函数的默认参数、占位符、重载
15 0
|
13天前
|
Unix 编译器 C语言
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
【C++航海王:追寻罗杰的编程之路】关键字、命名空间、输入输出、缺省、重载汇总
10 0
|
2月前
|
C++
在C和C++中,指针的算术操作
在C和C++中,指针的算术操作