一文彻底解决C++中的重载、重写和隐藏操作
往期C++系列相关内容:
网络相关内容:
epoll的水平触发LT以及边沿触发ET的原理及使用及优缺点
一文彻底解决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)
重写指的是在派生类中覆盖基类中的同名函数,重写就是重写函数体。
特点:
- 要求基类函数必须是虚函数
- 与基类的虚函数有相同的参数个数
- 与基类的虚函数有相同的参数类型
- 与基类的虚函数有相同的返回值类型
举个例子:
#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) | 隐藏 | 隐藏 |
希望本文可以让你系统的了解重载、重写和隐藏的特点和各自的区别。如果有错误内容,还请指出。
希望每一次发奋努力的背后,必有加倍的赏赐赋予。