以下是本人整理的C++基础知识点,内容并不包含全面的C++知识,只是对C++重点内容、特点进行整理和归纳。
6.1 C++运算符重载介绍
运算符重载介绍
功能
运算符在不同情况下有不同的功能,在不同情况下执行不同的操作
格式
返回值类型 operator运算符名称(形参表列){...}
operator
关键字,用于定义重载运算符的函数
可以将【operator 运算符名称】这一部分看做函数名
C++中默认的运算符重载
+
对不同类型(int、float ..)的数据进行加法操作
<<
位移运算符
输出流运算符,配合 cout 向控制台输出数据
运算符重载的本质
运算符重载是通过函数实现的,它本质上是函数重载
运算符重载函数和普通函数的区别
运算符重载函数除了函数名有特定的格式,其它地方和普通函数并没有区别
类内运算符重载和全局运算符重载
类内运算符重载
该重载只对该类的对象有效
例子
编译前:c3 = c1 + c2;
编译后:c3 = c1.operator+(c2);
过程:编译器检测+号左边(+号是左结合性)是一个类对象,就会调用该类的成员函数:operator+()
全局运算符重载
例子
定义:complex operator+(const complex &A, const complex &B){}
编译前:c3 = c1 + c2;
编译后:c3 = operator+(c1, c2);
过程:编译器检测+号两边都是 complex 对象,则调用重载函数: operator+()
运算符重载例子
例子1:类内运算符重载
//+运算符重载,实现复数运算
complex complex::operator+(const complex &A) const{
complex B;
B.m_real = this->m_real + A.m_real;
B.m_imag = this->m_imag + A.m_imag;
return B;
}
例子2:全局运算符重载
//+运算符重载,实现复数运算
complex operator+(const complex &A, const complex &B){
complex C;
C.m_real = A.m_real + B.m_real;
C.m_imag = A.m_imag + B.m_imag;
return C;
}
运算符重载相比于函数的特点
功能上,运算符重载和函数都能实现相同的功能
使用上,运算符重载用于运算更加简洁,扩展了原有运算符的功能
6.2 C++运算符重载规则
1、并不是所有的运算符都可以重载
可以重载的运算符
+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |=
+ << >> <<= >>= == != <= >= && || ++ -- , ->* -> ()
+ [] new new[] delete delete[]
不能重载运算符
长度运算符 sizeof
条件运算符 : ?
成员选择符.
域解析运算符::
2、重载不能改变运算符的优先级和结合性
3、重载不会改变运算符的用法
原有有几个操作数、操作数在左边还是在右边,这些不变
4、运算符重载函数不能有默认的参数
否则就改变了运算符操作数的个数,否则就改变了运算符操作数的个数
5、运算符重载函数既可以作为类成员函数,也可以作为全局函数
作为类成员函数
二元运算符的参数只有一个,一元运算符不需要参数
因为其中一个参数是隐含的,通过 this 指针隐式访问
作为全局函数
二元操作符就需要两个参数,一元操作符需要一个参数
其中必须至少有一个参数是自定义类型的对象
告知编译器使用自定义的运算符
不能所有参数都是基本数据类型,否则会修改内置类型的运算符性质,这是禁止的!
一般都需要在类中将该函数声明为友元函数
这样函数才能在类外访问类的 private 成员
6、箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载
6.3 以成员函数还是全局函数(友元函数)的形式重载运算符
转换构造函数
属于构造函数的一种。在初始化对象时,起到构造函数的作用;
在运算中,能够用来将其它类型转换为当前类类型
例子
Complex(double real); //Complex类的构造函数
Complex c1(25, 35);
Complex c2 = c1 + 15.6; //转换为Complex c2 = c1 + Complex (15.6);
以全局函数的形式重载运算符+的原因
保证 + 运算符能够对称处理操作数
Complex c2 = c1 + 15.6;//两者都准确,且结果相等
Complex c2 = 15.6 + c1; //
成员函数形式重载,运算符左边的操作数必须是类对象,不能是其它类型
因为运算时,会将左边操作数动作对象,调用该对象的重载函数;右边的操作数作为函数参数
转换构造函数只会转换作为函数参数的那个操作数
一般是运算符右边的操作数
如何选择这两种重载方式
优先考虑成员函数,这样更符合运算符重载的初衷
一部分运算符重载必须是全局函数,这样能保证参数的对称性
6.4 C++重载>>和<<(输入和输出运算符)
重载>>运算符
istream & operator>>(istream &in, complex &A){//重载
in >> A.m_real >> A.m_imag; //本质上等于cin>> A.m_real >> A.m_imag;
return in; //返回cin对象,实现连续输入
}
complex c1, c2;
cin>>c1>>c2;//使用
重载<<运算符
ostream & operator<<(ostream &out, complex &A){
out << A.m_real <<" + "<< A.m_imag <<" i ";
return out; //返回cout对象,实现连续输出
}
6.5 C++重载[]
特点
只能以成员函数形式重载
语法
返回值类型 & operator[ ] (参数);
可访问可修改,const对象不能使用
例子
int& Array::operator[](int i){
return m_p[i];
}
const 返回值类型 & operator[ ] (参数) const;
可访问不可修改,const对象能使用
例子
const int & Array::operator[](int i) const{
return m_p[i];
}
重载[ ]运算符以后
转换前:arr[i]
转换后:arr.operator[ ](i);
6.6 C++重载++和–(自增和自减运算符)
介绍
自增++和自减--都是一元运算符,它的前置形式和后置形式都可以被重载
语法
classType operator++(); //++i,前缀式自加
classType operator++(int); //i++,后缀式自加
加int参数只做函数区分,没有实际意义
6.7 C++重载new和delete运算符
特点
可以是类的成员函数,也可以是全局函数
一般情况下,内建的内存管理运算符就够用了
类中没有定义 new 和 delete 的重载函数,那么会自动调用内建的 new 和 delete 运算符
语法
void * className::operator new( size_t size ){...}
参数:申请内存的长度
返回void*类型
void * operator new( size_t size )( size_t size ){...}
void className::operator delete( void *ptr){...}
参数:void*型指针
void operator delete( void *ptr){...}
6.8 C++重载()(强制类型转换运算符)
介绍
类型的名字(包括类的名字)本身也是一种运算符,即类型强制转换运算符
只能重载为成员函数,不能重载为全局函数
编译器在认为需要类型转换时,就会隐式调用强制转换
语法
(类型名)对象,等价于对象.operator 类型名()
例子
double():double类型强制转换运算符
double(i)就是调用内建的double类型强制转换运算符,将 i 转换为double,然后将结果返回
例子
//重载double强制类型转换运算符
operator double() { return real; } //无需写返回类型
//调用
(double)c; //强制转换c的类型
double n = 2 + c; //等价于double n = 2 + c. operator double()
6.9 运算符重载注意事项
重载后运算符的含义,应该符合原有用法习惯
运算符可以重载为全局函数,然后声明为类的友元
必要时需要重载赋值运算符 =,以避免两个对象内部的指针指向同一片存储空间