目录
- 一、运算符重载(二元运算符)
-
- 1.1概念
- 1.2目的
- 1.3程序举例
- 1.4 运算符重载原理fa+fb讲解
- 1.5对1.3运用运算重载符fa+fb进行改进(全局形式)
- 1.6对1.3运用运算重载符fa+fb进行改进(成员函数形式)
- 1.7 运算符重载fa*=fb
- 1.7例子:分数和整数相加
- 1.8友元函数
-
- 1.8.1 方式一:使用公开的访问接口
- 1.8.2方式二:友元函数
- 1.9成员函数、静态函数、友元函数特性
- 1.10两个特殊的运算符
- 1.11其他的二元运算符
- 二、运算符重载(一元运算符)
-
- 三、运算符重载的限制
-
- 3.1不能重载的运算符
- 3.2只能对已有的运算符进行重载
- 3.3不能仅对基本类型进行运算符重载
- 3.4不能改变运算符的运算特性
- 3.5只能是重载成 成员形式的运算符号
- 四、只能是成员的运算符重载
-
- 4.1 = 和 [ ] 讲解
- 4.2 ()讲解
- 4.3 * 和 ->讲解
- 五、new和delete / new[]和delete[]重载
-
- 5.1 new和delete 与 malloc和free的比较
- 5.2重载new和delete
一、运算符重载(二元运算符)
1.1概念
是函数的特殊表现形式
1.2目的
为了方便编程
代码更加直观
1.3程序举例
设计一个类,叫分数类
分数类特征:
分子
分母
分数类功能:
显示分数
运算:
+ Fraction add(){}
-
*
/
全局区定义一个函数,代表两个分数相加
#include
using namespace std;
class Fraction{
public:
int x;
int y;
Fraction(int x=0,int y=1):x(x),y(y){
}
void show(){
cout << x << '/' << y << endl;
}
};
Fraction addFraction(const Fraction& fa,
const Fraction& fb){
return Fraction(fa.x*fb.y + fa.y*fb.x,fa.y*fb.y);
}
int main(){
Fraction fa(1,3);
fa.show();
Fraction fb(1,2);
fb.show();
Fraction fc = addFraction(fa,fb);
fc.show();
}
1.4 运算符重载原理fa+fb讲解
Fraction fa;
Fraction fb;
fa + fb;
遇到fa+fb系统解析的过程:
首先去类的成员函数中找一个成员函数
operator+(const Fraction& fb)
/*"operator+"是函数名*/
fa + fb; ---> fa.operator+(const Fraction& fb)
/*即把fb当成fa.operator+()的参数*/
若找不到,则去全局区找一个全局函数
operator+(const Fraction& fa,const Fraction& fb);
注意:你把函数名operation+换成operation-就完成两个数的相减
换成operation*就完成两个数的相乘
换成operation/就完成两个数的相除
1.5对1.3运用运算重载符fa+fb进行改进(全局形式)
把函数名addFraction改为operator+即可
#include
......
Fraction operator+(const Fraction& fa,
const Fraction& fb){
......
}
int main(){
......
Fraction fc = fa+fb;
......
}
1.6对1.3运用运算重载符fa+fb进行改进(成员函数形式)
#include
......
class Fraction{
......
Fraction operator+(const Fraction& fb){
return Fraction(this->x*fb.y +
this->y*fb.x,this->y*fb.y);
}
};
int main(){
......
Fraction fc = fa+fb;
......
}
1.7 运算符重载fa*=fb
Fraction fa;
Fraction fb;
fa *= fb;
程序如下:
#include
......
class Fraction{
......
void operator*=(const Fraction& fb){
this->x*=fb.x;
this->y*=fb.y;
}
};
int main(){
......
fa*=fb;
fa.show();
......
}
1.7例子:分数和整数相加
返回一个double,让一个分数和一个整数相加
#include
......
double operator+(const Fraction& f,int fb){
return 1.0*f.x/f.y + x;
}
int main(){
......
double res = fb+100;
cout << res << endl;
}
1.8友元函数
在说友元函数之前,请你先看1.8.1,然后再看1.8.2了解友元函数
设计一个整数包装类
1.8.1 方式一:使用公开的访问接口
使用公开的访问接口,即使用函数int getData()const(){}
达到访问私有成员data的目的。
#include
using namespace std;
class Integer{
int data;
public:
Integer(int data=0):data(data){
}
void show(){
cout << data << endl;
}
Integer operator+(const Integer& i){
return Integer(data + i.data);
}
public:
int getData()const{
return data;
}
};
Integer operator-(const Iconst& ia,const Integer& ib){
return Integer(ia.getData() - ib.getData());
}
int main(){
Integer ia(100);
Integer ib(1);
ia.show();
ib.show();
Integer ic = ia+ib;
ic.show();
Integer id = ia-ib;
id.show();
}
1.8.2方式二:友元函数
友元函数的本质就是全局,但友元函数获得了对私有成员的访问
权力。
你可以把友元函数理解为类的好朋友,它虽然不属于类的成员函数
但是他可以访问类的私有成员。两个人的关系比较好嘛。
#include
using namespace std;
class Integer{
int data;
public:
Integer(int data=0):data(data){
}
void show(){
cout << data << endl;
}
friend Integer operator-(const Iconst& ia,const Integer& ib);
};
Integer operator-(const Iconst& ia,const Integer& ib){
return Integer(ia.data - ib.data);
}
int main(){
Integer ia(100);
Integer ib(1);
Integer id = ia-ib;
id.show();
}
1.9成员函数、静态函数、友元函数特性
对类的私有成员的访问
受类型作用域 和 权限限制
需要通过对象去访问
成员函数具有以上三个特性
静态函数具有以上前两个特性
友元函数只有第一个特性
1.10两个特殊的运算符
<<
>>
Integer ia;
cout << ia << endl;
cout ------ osteram&
注意:流类型的对象不能拷贝、不能加const修饰
cout << ia的解析:
先去ostream类中,找一个成员函数,叫
operator<<(const Integer& i)
当然,这不现实,因为头文件ostream里的operator<<函数
没有Inteher,Integer是你自己命名的。
因此这种方法不现实
这时,就会去全局区找一个全局函数,叫:
operator<<(ostream& os,const Integer& i);
输出流-程序举例:
#include
using namespace std;
class Integer{
int data;
public:
Integer(int data=0):data(data){
}
void show(){
cout << data << endl;
}
Integer operator+(const Integer& i){
return Integer(data + i.data);
}
friend Integer operator-(const Iconst& ia,const Integer& ib);
friend ostream& operator<<(ostream& os,const Integer& i);
};
Integer operator-(const Iconst& ia,const Integer& ib){
return Integer(ia.data - ib.data);
}
ostream&operator<<(ostream& os,const Integer& i){
os << i.data;
return os;
}
int main(){
Integer ia(100);
Integer ib(1);
Integer ic = ia-ib;
ic.show();
cout << ic << endl;
}
补充一下 输入流函数:
/*在类中声明友元函数*/
friend istream& operator>>(istream& is,Integer& i)
编写函数:
istream& operator>>(istream& is,Integer& i){
return is >> i.data;
}
1.11其他的二元运算符
== (以什么标准判断两个对象是否相等?)
答:两个判断标准:值/地址
int x=10;
int y=10;
== 程序举例:
#include
using namespace std;
class Integer{
int data;
public:
Integer(int data=0):data(data){
}
void show(){
cout << data << endl;
}
Integer operator+(const Integer& i){
return Integer(data + i.data);
}
bool operator==(const Integer& i){
return data==i.data;
}
};
int main(){
Integer ia(100);
Integer ib(100);
if(ia == ib){
cout << "ok" << endl;
}
}
二、运算符重载(一元运算符)
2.1 一元运算符
-(负号) ! ~ ++ --
使用方法:
我们暂且用#a表示(#表示一元运算符、a表示对象)
#a的解析过程:
首先去a对象对应的类型中找一个成员函数operator#()
找不到的话,就去全局找一个全局函数叫operator#(a)
全局的话,你得把a传进去
a#解析过程:(即运算符在对象后面)
首先去a对象对应的类型中找一个
成员函数operator#(int)
找不到,就去全局区找一个全局函数叫
operator#(a,int)
2.2 程序举例:
#include
using namespace std;
class Integer{
int data;
public:
Integer(int data=0):data(data){
}
Integer operator!(){
return Integer(!data);
}
Integer operator-(){
return Integer(-data);
}
Integer& operator++(){
++data;
return *this;
}
const Integer operator++(int){
return Integer(data++);
}
friend ostream& operator<<(ostream& os,const Integer& i);
friend Integer& operator--(Integer& i);
friend const Integer operator--(Integer& i,int);
};
ostream& operator<<(ostream& os,const Integer& i){
return os << i.data;
}
Integer& operator--(Integer& i){
--i.data;
return i;
}
const Integer operator--(Integer& i,int){
return Integer(i.data--);
}
int main(){
Integer ia(100);
cout << !ia << endl;
cout << -ia << endl;
cout << ++ia << endl;
cout << ++ia << endl;
cout << ia++ << endl;
cout << ia-- << endl;
cout << --ia << endl;
}
三、运算符重载的限制
3.1不能重载的运算符
:: 作用域运算符
. 成员运算符
.* 成员指针解引用
sizeof 计算类型大小的
? : 三元运算符
typeid 获取类型信息(返回typeinfo)
3.2只能对已有的运算符进行重载
只能对已有的运算符进行重载,不能发明新的运算符
3.3不能仅对基本类型进行运算符重载
运算符重载中至少有一个类型是非基本类型
3.4不能改变运算符的运算特性
不能把一元改成二元的
3.5只能是重载成 成员形式的运算符号
如 =(赋值运算符)(最好是成员的+= -= /= ^=)
[](取下标运算符)
()
* ->
3.5这个太重要了,我们拿到第四章专门讲
四、只能是成员的运算符重载
4.1 = 和 [ ] 讲解
自定义数组 Array
程序举例:(以=和[]为例)
#include
using namespace std;
class Array{
int size;
int len;
int *datas;
public:
Array(int len = 5):size(0),len(len){
datas = new int[len];
}
~Array(){
delete[] datas;
datas = NULL;
}
Array(const Array& a){
cout << "Array(Array&)" << endl;
size=a.size;
len = a.len;
datas = new int[len];
for(int i=0;i<size;i++){
datas[i] = a.datas[i];
}
}
void push_back(int da){
if(size >= len){
expend();
}
datas[size++]=da;
}
void expend(){
int *temp = datas;
len = 2*len + 1;
datas = new int[len];
for(int i=0;i<size;i++){
datas[i] = temp[i];
}
delete[] temp
}
void show(){
if(size == 0){
cout << "[]" << endl;
return;
}
cout << "[";
for(int i =0;i<size-1;i++){
cout << datas[i] << ",";
}
cout << datas[size-1] << "]" << endl;
}
Array& operator=(const Array& arr){
if(this!=&arr){
size=arr.size;
len=arr.len;
int *temp = datas;
datas = new int[len];
for(int i=0;i<size;i++){
datas[i] = arr.datas[i];
}
delete[] temp;
}
return *this;
}
int operator[](int ind)const{
return dadas[ind];
}
};
void foo(){
Array arra;
arra.push_back(9);
arra.push_back(5);
arra.push_back(2);
arra.push_back(7);
arra.push_back(2);
arra.push_back(2);
cout << "-----------" << endl;
cout << arra[0] << endl;
Array arrb;
arrb = arra;
arrb.show();
}
int main(){
foo();
}
一个练习
#include
using namespace std;
class Integer{
int *data;
public:
Integer(int data){
this->data = new int(data);
}
~Integer(){
delete data;
}
Integer(const Integer& i){
data=new int(*(i.data));
}
Integer& operator=(){
if(this!=&i){
*data = *(i.data);
}
return *this;
}
friend ostream& operator<<(ostream& os,const Integer& i){
return os << *(i.data);
}
};
int main(){
Integer ia=100;
Integer ib=ia;
cout << ib << endl;
Integer ic;
ic=ib;
cout << ic << endl;
}
4.2 ()讲解
()运算符作用:
①负责类型转换
把当前对象类型变成一个类型。
operator 类型 (){
return 类型的对象;
}
②函数对象(可以像函数一样去使用的对象)
返回值类型 operator()(参数列表 ){
return 值;
}
程序举例:
#include
using namespace std;
class Product{
int count;
double price;
public:
Product(int count=0,double price=0.0)
:count(count),price(price){
}
operator int (){
return count;
}
operator double (){
return price;
}
double operator()(int c,double p){
return c*p;
}
};
int main(){
Product product(100,1.15);
int count=(int)product;
cout << count << endl;
double price = (double)product;
cout << price << endl;
product(1,2.5);
cout << product(1,2.5) << endl;
}
4.3 * 和 ->讲解
把一个不是指针的类型,当作指针类型来使用。(这就得用运算
重载符了)
程序举例:
#include
using namespace std;
class A{
public:
A(){
cout << "A()" << endl;
}
~A(){
cout << "~A()" << endl;
}
void showa(){
cout << "this A showa()" << endl;
}
};
class myauto_ptr{
A *data;
public:
myauto_ptr(A *data=NULL):data(data){
}
~myauto_ptr(){
delete data;
}
void show(){
cout << "this is auto_ptr show()"
}
A* operator->(){
return data;
}
A& operator*(){
return *data;
}
};
void foo(){
A *pa=new A();
myauto_ptr mptr(pa);
mptr.show();
mptr->showa();
mptr.operator->()->showa();
(*mptr).showa();
}
int main(){
foo();
}
五、new和delete / new[]和delete[]重载
注:会new和delete的重载实现就行,new[]和delete[]就是在new和delete的基础上
加了一个[]
5.1 new和delete 与 malloc和free的比较
new比malloc多做了什么?
答:入如果类的成员是类类型,则自动创建这个成员
自动处理类型转换
自动调用构造函数
delete比free多做了什么?
delete比free多调用了析构函数
程序举例:
#include
#include
using namespace std;
class A{
public:
A(){
cout << "A()" <<endl;
}
~A(){
cout << "~A()" << endl;
}
};
class B{
A a;
public:
B(){
cout << "B()" << endl;
}
~B(){
cout << "~B()" << endl;
}
};
int main(){
B *pb = static_cast<B*>(malloc(sizeof(B)));
B *pb2 = new B();
free(pb);
delete pb2;
}
5.2重载new和delete
void* operator new(size_t size)
void* operator delete(void* ptr);
程序举例:
#include
#include
using namespace std;
class Date{
int year;
int month;
int day;
public:
Date(int year=0,int month=0,int day =0)
:year(year),month(month),day(day){
cout << "Date(int,int,int)" << endl;
}
~Date(){
cout << "~Date()" << endl;
}
static void *operator new(size_t size){
cout << "my operator new" << size << endl;
return malloc(size);
}
static void operator delete(void *ptr){
cout << "operator delete" << endl;
free(ptr);
}
}
};
int main(){
Date *date = new Date();
delete date;
}