参考:/cplusplus/cpp-overloading.html
/CaiNiaoZJ/archive//08/12/2136598.html
前言:
运算符重载和函数重载体现了面向对象技术的多态性。多态性机制不仅增加了面向对象软件系统的灵活性,进一步减少了冗余信息,而且显著提高了软件的可重用性和可扩充性。
从实现的角度来讲,多态性可以划分为两类:编译时的多态性和运行时的多态性。在C++语言中,编译时的多态性主要是通过函数重载和运算符重载实现的。
本文主要讲的是编译时多态,因为编译时多态主要是通过函数重载和运算符重载实现的。
运行时多态之后再讲。
C++允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
一、C++ 中的函数重载
概念
重载:是指运行存在多个同名函数,而这些函数的参数列表不同(参数个数、类型、顺序),不能使用返回值作为区分。
关键词:同一作用域内,具有相同函数名,不同参数列表
原理
重命名机制(name mangling):
编译器根据函数不同的参数表,对同名函数的名称进行函数修饰,从而这些同名函数就成为了不同的函数(至少对于编译器来说是这样的)。该过程在编译器间就已经确定了,也就是说在编译期就绑定了(早绑定)。
区分
C语言是不支持函数重载的,这里涉及另外一个知识点:C++在兼容C时的extern "C"的用法。
代码实例
#include<iostream>using namespace std;void print(int i){cout<<"print a integer :"<<i<<endl;}void print(string str){cout<<"print a string :"<<str<<endl;}int main(){print(12);print("hello world!");return 0;}
二、C++ 中的运算符重载
2.0 使用全局函数进行运算符重载(数据成员为public属性)
C++就为运算符重载提供了一种方法,即运算符重载函数。其函数名字规定为operator后紧跟重载运算符。比如:operator+(),operator*()等。现在我们给出一个加法运算符的重载函数用于完成复数的加法运算:
#include <iostream>using namespace std;class Complex //复数类{public:double real;//实数double imag;//虚数Complex(double real=0,double imag=0){this->real=real;this->imag=imag;}};Complex operator+(Complex com1,Complex com2)//运算符重载函数{return Complex(com1.real+com2.real,com1.imag+com2.imag);}int main(){Complex com1(10,10),com2(20,20),sum;sum=com1+com2;//或sum=operator+(com1,com2)cout<<"sum的实数部分为: "<<sum.real<<endl;cout<<"sum的虚数部分为: "<<sum.imag<<"i"<<endl;return 0;}
输出:
sum的实数部分为: 30sum的虚数部分为: 30i
上述示例中的运算符重载函数是不属于任何的类,是全局的函数。因为在Complex类(复数类)中的数据成员是公有的性质,所以运算符重载函数可以访问。但如果定义为私有的呢,那该怎么办。其实,在实际的运算符重载函数声明当中,有两种方法:
定义其为要操作类的成员函数或类的友元函数。
2.1 运算符重载函数作为类的友元函数的形式:
友元函数重载双目运算符(有两个操作数,通常在运算符的左右两则),参数表中的个数为两个。若是重载单目运算符(只有一个操作数),则参数表中只有一参数。
class 类名{friend 返回类型 operator运算符(形参表);}类外定义格式:返回类型 operator运算符(参数表){函数体}
1) 友元函数重载双目运算符(+)
#include <iostream>using namespace std;class Complex //复数类{//私有数据 private:double real;//实数double imag;//虚数public: Complex(double real=0,double imag=0){this->real=real;this->imag=imag;}//友元函数重载双目运算符friend Complex operator+(Complex com1,Complex com2);void showSum();};Complex operator+(Complex com1,Complex com2)//运算符重载函数{return Complex(com1.real+com2.real,com1.imag+com2.imag);}void Complex::showSum(){if(imag>=0){cout<<real<<"+"<<imag<<"i"<<endl;}else{cout<<real<<imag<<"i"<<endl;}}int main(){Complex com1(10,10),com2(20,20),sum;sum=operator+(com1,com2);//或 sum=com1+com2sum.showSum();return 0;}
2) 友元函数重载单目运算符(++):
#include <iostream>using namespace std;class Point//坐标类{private:int x;int y;public:Point(int x,int y){this->x=x;this->y=y;}friend void operator++(Point& point);//友元函数重载单目运算符++void showPoint();};void operator++(Point& point)//友元运算符重载函数{++point.x;++point.y;}void Point::showPoint(){std::cout<<"("<<x<<","<<y<<")"<<std::endl;}int main(){Point point(10,10);++point;//或operator++(point)point.showPoint();//输出坐标值return 0;}
输出
(11,11)
2.2 运算符重载函数作为类的成员函数的形式:
对于成员函数重载运算符而言,双目运算符的参数表中仅有一个参数,而单目则无参数。同样的是重载,为什么和友元函数在参数的个数上会有所区别的。原因在于友元函数,没有this指针。
class 类名{返回类型 operator 运算符(形参表);}类外定义格式:返回类型 类名:: operator 运算符(形参表){函数体;}
1) 成员函数重载双目运算符(+):
#include <iostream>using namespace std;class Complex //复数类{//私有数据 private:double real;//实数double imag;//虚数public: Complex(double real=0,double imag=0){this->real=real;this->imag=imag;}//成员函数重载双目运算符Complex operator+(Complex com1);void showSum();};Complex Complex::operator+(Complex com1){return Complex(real+com1.real,imag+com1.imag);}void Complex::showSum(){if(imag>=0){cout<<real<<"+"<<imag<<"i"<<endl;}else{cout<<real<<imag<<"i"<<endl;}}int main(){Complex com1(10,10),com2(200,200),sum;sum=com1+com2;//或 sum=com1.operator+(com2);sum.showSum();return 0;}
2)成员函数重载单目运算符(++)
#include <iostream>using namespace std;class Point//坐标类{private:int x;int y;public:Point(int x,int y){this->x=x;this->y=y;}void operator++();//成员函数重载单目运算符++void showPoint();};void Point::operator++()//成员运算符重载函数{++x;++y;}void Point::showPoint(){std::cout<<"["<<x<<","<<y<<"]"<<std::endl;}int main(){Point point(10,10);++point;//或operator++(point)point.showPoint();//输出坐标值return 0;}
输出
[11,11]
三、重载输出运算符<<
#include<iostream>using namespace std;class People{public:People(int id,int pwd):m_id(id),m_pwd(pwd){}~People(){}friend ostream& operator<< (ostream &os,People p);private:int m_id;int m_pwd;};ostream& operator << (ostream &os, const People p){os<<"your id is:"<<p.m_id<<" and password is:"<<p.m_pwd<<endl;return os;}int main() {People a(1,123);People b(2,456);cout << a<<b;}输出:your id is:1 and password is:123your id is:2 and password is:456
注:
输出运算符的第一个形参是非常量ostream对象的引用。之所以非常量是因为向流写入内容会改变其状态;而该形参是引用是因为我们无法直接复制一个ostream对象。
第二个形参一般是常量引用,该常量是我们要打印的类类型,之所以是常量是因为我们打印一般不会改变对象内容;是引用是我们希望避免复制形参。
返回值返回的是ostream类对象的引用,为了与其他输出运算符保持一致,operator<<一般要返回它的ostream形参。同时为了进行连续的运算,如cout<<a<<b; 先打印类对象a,返回对象引用后继续打印b。
如果觉得《C++ 重载运算符和重载函数》对你有帮助,请点赞、收藏,并留下你的观点哦!