C++ 重载

引言

重载的本质

重载(overloading)是同一符号在不同作用域的不同应用条件下具有不同的语义。这个符号可以是函数,运算符,也就是一物多用

函数重载

函数重载:定义同名但参数类型与数量不同的函数,编译系统根参数的匹配规则来决定调用哪一个函数

前置内容(带缺省值的函数)

带缺省值的函数

函数在说明或函数定义中,形参指定了一个数值,则称此函数为带缺省值的函数,指定的值称为缺省值

Example
1
2
3
//带缺省值的函数声明:
float area(float r=6.5)
//6.5就是缺省值

在调用时,如果不传参数,使用默认值,就会默认形参等于缺省值

1
area();//默认 r=6.5

不使用默认值

1
area(7.5);// r=7.5
带多个缺省参数的函数

如果函数有多个缺省参数,则缺省参数必须是 从右向左定义,并且在一个缺省参数的右边不能有 未指定缺省值的参数。(缺省值集中在参数表右侧)

1
2
void f1( float a , int b=6 , int c , char d='a' );//错误定义
void f2( float a , int c , int b=6 , char d='a' );//正确定义

调用形式可以为:

1
2
3
f2( 3.5 , 5 , 3 , 'x' );
f2( 3.5 , 5 , 3 );
f2( 3.5 , 5 );

不带缺省的得函数重载

函数重载:定义同名但参数类型与数量不同的函数,编译系统根据参数的匹配规则来来决定调用哪一个函数

1
2
3
4
5
6
7
8
9
int max( int a , int b , int c ) {
	...
}
int max( int a , int b ) {
	...
}
double max(double a , double b ) {
	...
}

注意:不能出现函数参数个数,参数类型都相同,只有函数返回值不同的同名函数。 因为系统将无法从调用形式上判断调用哪个函数

1
2
3
4
5
6
int max( int a , int b ) {
	...
}
bool max( int a , int b ) {
	...
}

带缺省值的函数重载

一般带缺省值的函数不能进行重载,容易出现错误 错误实例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int max( int a , int b , int c=1 ) {
	...
}
int max( int a , int b ) {
	...
}

int main() {
	max(1,2) ;
}

此时系统无法匹配正确的函数,不能实现函数重载(静态多态)

一个函数不能即作为重载函数,又 作为有默认参数的函数! (这是一个建议,其实并不绝对,只要让系统能匹配到唯一的函数就行)

运算符重载

前置内容(C++ 类与对象)

运算符重载本质上是函数重载,将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参(看个乐呵就行)

为什么需要运算符重载

C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型。运算符重载允许把C++标准运算符应用于自定义数据类型的对象,与函数重载类似,对已有的运算符赋予新的含义,用一个运算符表示不同功能的运算, 这就是运算符重载

运算符重载的例子

类的定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class complex {
    public:
        complex();//默认构造函数
        complex(double,double);//初始化构造函数
        complex(double);//强制转换构造函数
//*****************************************************//
       //下面是二选一
        complex operator + (complex&);//运算符重载成员函数实现
        complex operator - (complex&);//运算符重载成员函数实现
        
        friend complex operator + (complex&,complex&);//友元函数实现
        friend complex operator - (complex&,complex&);//友元函数实现
        
//****************************************************//
        friend istream& operator >> (istream& , complex&);//istream类>>运算符重载
        friend ostream& operator << (ostream& , complex&);//ostream类<<运算符重载
    private:
        double real , imag ;
};

成员函数重载运算符

隐含this指针,左侧自定义类型

1
c3 = c1+c2 ;

翻译为

1
c3 = c1.operator+(c2);

参数个数=原操作数个数-1(后置++、–除外)

模板
1
2
3
数据类型(返回值类型) 类名()::operator 运算符( 形参表 ) {
	重载处理
} 
具体例子
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
complex complex::operator + (const complex &c1) {
    complex c2 ;
    c2.real = real+c1.real ;
    c2.imag = imag+c1.imag ;
    return c2 ;
}

complex complex::operator - (const complex &c1) {
    complex c2 ;
    c2.real = real-c1.real ;
    c2.imag = imag-c1.imag ;
    return c2 ;
}

友元函数重载运算符

1
c3 = c1 + c2 ;

翻译为

1
c3 = operator+(c1,c2);//友元函数

参数个数=原操作数个数 (至少有一个自定义类型形参)

模板
1
2
3
friend 数据类型(返回值类型) 类名():: operator 运算符( 形参表 ) {
	重载处理
} 
具体例子
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
complex complex::operator + (const complex &c1 , const complex &c2) {
    complex c ;
    c.real = c2.real+c1.real ;
    c.imag = c2.imag+c1.imag ;
    return c ;
}

complex complex::operator - (const complex &c1 , const complex &c2) {
    complex c ;
    c.real = c1.real-c2.real ;
    c.imag = c1.imag-c2.imag ;
    return c ;
}

重载«和»运算符

«重载函数和»重载函数只能定义为友元函数,不能定义为成员函数, 因为«和»运算符有两个形参,并且第一个形参不是自定义类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//类中的友元函数定义
//***********************************//
friend istream& operator >> (istream& , complex&);//istream类>>运算符重载
friend ostream& operator << (ostream& , complex&);//ostream类<<运算符重载
//***********************************//

//复数的自定义输入输出
istream& operator >> (istream& input , complex&c ) {
    input >> c.real >> c.imag ;
    return input ;

}

ostream& operator << (ostream& output , complex&c ) {
    output << c.real << '+' << c.imag << 'i' << endl ;
    return output ;
}

重载单目运算符

成员函数重载

前置++

1
2
//前置
complex operator ++();

后置++

1
2
3
//后置
complex operator ++(int);
//如果在形参中添加int占位参数,编译器会识别出这是后置++
友元函数重载

前置++

1
2
//前置
friend complex operator ++ (complex);

后置++

1
friend complex operator ++ (complex,int);

运算符重载的规则(看个乐呵就行)

• 运算符重载不允许发明新的运算符。如@ • 不能改变运算符操作对象的个数,如+是双目运算 • 运算符被重载后,优先级和结合性不会改变 • 经重载的运算符至少有一个参数为自定义类型,否则系 统已经实现

运算符重载的实现形式

运算符重载函数可以声明为 类成员函数 也可以是 类的友元函数 ,还可以是 普通函数

推荐使用成员函数或是友元函数实现

(主要因为私有成员的访问问题) 实现运算符重载的方式——既然是操作符重载,一般会访问类的私有成员变量,根据类的封装性要求,除了友元函数外,其他任何外部操作都是违规的,所以不推荐用 普通函数 来重载操作符

experience
使用 Hugo 构建
主题 StackJimmy 设计