Day6知识点:
1. 在运算符重载时尽量遵循原有默认的规则,如以下代码
int a , b , c;
(a + b) = c; //是错误的
而在运算符重载中:
Complex Complex::operator+(Complex& another)
{
Complex t;
t._x = _x + another._x;
t._y = _y + another._y;
return t;
}
Complex c1(1,2) ,c2(2,3);
(c1 + c2) = c; //是正确的,但不遵循默认语法规则
2. C++不允许用户自定义新的运算符,只能对已有的C++运算符进行重载
C++允许重载的运算符:
C++不允许重载的运算符只有四个:
3. 对于双目运算符
重载为成员(即成员函数)的话,需要一个参数,重载为友元(即全局函数)的时候需要两个参数
const Complex operator+(Complex& another);
friend Complex operator+(Complex& a,Complex& b);
对于单目运算符
重载为成员的话,不需要参数,重载为友元时需要一个参数。
三目运算符无法重载。
4.
若函数重载为
void Complex::operator+=(const Complex &another)
{
this->_x += another._x;
this->_y += another._y;
}
x +=y; //可行
x += y += z; //不可行,不能用做右值,所以应有返回值
若函数重载为
Complex Complex::operator+=(const Complex &another)
{
this->_x += another._x;
this->_y += another._y;
return *this;
}
x +=y; //可行
x += y += z; //可行
(x += y) += z;// 不可行,不能用作左值,所以应返回引用
最终确认版本为:
Complex& Complex::operator+=(const Complex &another)
{
this->_x += another._x;
this->_y += another._y;
return *this;
}
逐步迭代,尽量使语法规则接近自然语言。
例1.+操作符重载
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(float x = 0,float y = 0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<" , "<<_y<<")"<<endl;
}
// friend Complex operator+(Complex& a,Complex& b);
const Complex operator+(Complex& another);
private:
float _x;
float _y;
};
//Complex operator+(Complex& a,Complex& b)
//{
// Complex t;
// t._x = a._x + b._x;
// t._y = a._y + b._y;
// return t;
//}
const Complex Complex::operator+(Complex& another)
{
Complex t;
t._x = _x + another._x;
t._y = _y + another._y;
return t;
}
int main()
{
Complex c1(1,2) ,c2(2,3);
// Complex c = c1 + c2;
// Complex c = operator+(c1,c2);
Complex c = c1.operator+(c2);
c1.dis();
c2.dis();
c.dis();
// (c1 + c2) = c;
return 0;
}
例2.+=操作符重载
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(float x = 0,float y = 0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<" , "<<_y<<")"<<endl;
}
Complex& operator+=(const Complex &another);
private:
float _x;
float _y;
};
Complex& Complex::operator+=(const Complex &another)
{
this->_x += another._x;
this->_y += another._y;
return *this;
}
int main()
{
int a = 10, b = 20, c = 30;
// a += b;
// b += c;
// a += b += c;
(a += b) += c;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
cout<<"--------------------------"<<endl;
Complex x(10,0), y(20,0), z(30,0);
// x += y;
// y += z;
// x += y += z;
(x += y) += z;
x.dis();
y.dis();
z.dis();
return 0;
}
5.
1).单目运算符-的重载
若重载函数为 Complex operator-()
{
return Complex(-this->_x,-this->_y);
}
则:
Complex c(1,1);
Complex t = -c; //可行,符合常用规则
Complex t = -(-c); //可行,符合常用规则
Complex m(2,2);
-c = m; //可行,不符合常用规则
若将重载函数改为
const Complex operator-()
{
return Complex(-this->_x,-this->_y);
}
-c = m; //不能通过
t = -(-c); //也不能通过
因为-c调用时返回的const Complex,但是const类对象只能调用const成员函数
所以应改为:
const Complex operator-()const
{
return Complex(-this->_x,-this->_y);
}
-c = m; //不能通过
t = -(-c); //能通过
例3.单目操作符-(负号)重载
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(float x = 0,float y = 0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<" , "<<_y<<")"<<endl;
}
const Complex operator-()const
{
return Complex(-this->_x,-this->_y);
}
private:
float _x;
float _y;
};
int main()
{
int n = 5;
cout<<n<<endl;
cout<<-n<<endl;
cout<<n<<endl;
cout<<-(-n)<<endl;
// -n = 30; // 返回值不可以赋值,所以用const
Complex c(1,1);
// Complex t = -c;
Complex t = -(-c);
// Complex t(2,2);
// -c = t;
c.dis();
t.dis();
return 0;
}
2)双目运算符<<与>>的重载
<<是双目运算符,左边是cout的类型ostream&,右边是Complex&类型,因为可以连续使用,所以返回值也为ostream&的类型,如果将operator<<()声明为成员函数的话,那么 cout.operator<<()是成立的,即但是operator并不是Complex类的成员函数,而是cout类的成员函数,所以只能声明为友元函数
friend ostream& operator<<(ostream& os,const Complex& c)
{
cout<<"("<<c._x<<" , "<<c._y<<")"<<endl;
}
同理,流输入运算符>>重载为
friend istream& operator>>(istream& is,Complex& c) //此处由于有数据流入c,所以不可加const
{
is>>c._x>>c._y;
return is;
}
如若把流输入运算符在myString中重载,考虑到不能确定_str容量的大小,应该这样定义流输入运算符
istream& operator>>(iostream &is,myString &s)
{
delete s._str; //初始化时会new一份空间给它,所以需事先delete掉这份空间
char buf[BUFSIZ];
int len = strlen(buf);
s._str = new char[len+1];
strcpy(s._str,buf);
return is;
}
例4.双目操作符<<与>>的重载
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(float x = 0,float y = 0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<" , "<<_y<<")"<<endl;
}
friend ostream& operator<<(ostream& os,const Complex& c) //可移植性强
{ //把参数中的Complex修改后
cout<<"("<<c._x<<" , "<<c._y<<")"<<endl; //可直接移植到myString中声明
return os; //然后略微修改函数体即可
} //
friend istream& operator>>(istream& is,Complex& c) //此处由于有数据流入c,所以不可加const
{
is>>c._x>>c._y;
return is;
}
private:
float _x;
float _y;
};
int main()
{
Complex c(1,2);
// c.dis;
cin>>c;
cout<<c<<endl;
return 0;
}
例5.发送邮件作业
#include <iostream>
using namespace std;
class Mail;
class Sender
{
public:
Sender(string s):_addr(s){}
Sender operator <<(Mail& mail);
private:
string _addr;
};
class Mail
{
public:
Mail(string _t,string _c):_title(_t),_content(_c) {}
friend Sender Sender:: operator <<(Mail& mail);
private:
string _title;
string _content;
};
Sender Sender::operator <<(Mail& mail)
{
cout<<_addr<<endl;
cout<<mail._title<<endl;
cout<<mail._content<<endl;
return *this;
}
int main()
{
Sender sender("666666@163.com");
Mail mail1("note","holiday 8/26-8/27");
Mail mail2("note","cancel holiday.");
sender<<mail1<<mail2;
return 0;
}
(float)5/8; //C中强制类型转化,正确
static_cast<float>(5)/8; //C++中强制类型转化,正确
float(5)/8; //错误
7.类型转换构造器
转换构造函数,本质上是一个构造函数,是只有一个参数的构造函数,作用:把其他类型显式转换为自身的类型,广泛运用于赋值,传参
class Point3D
{
public:
Point3D(const Point2D &p2)
{
this->_x = p2._x;
this->_y = p2._y;
this->_z = 0;
}
};
Point2D p2(1,2);
Point3D p3(3,4,5);
p3 = p2; //转换构造函数赋值,先把隐式p2升级为3D类型,然后发生的是一种赋值,利用构造函数实现
convert(p2); //转换构造函数传参
8.explicit关键字
若在转换构造函数前加上explict关键字,则在转换过程中不能隐式转换,只能显示转换
p3 = (Point3D)p2;
convert((Point3D)p2);
9.类型转化操作符函数
作用:把自身类型隐式或显式转换为其他类型,转换函数无参数无返回
class Point3D
{
public:
operator Point2D(void)
{
return Point2D(this->_x,this->_y); //将3D转换成3D,特例,不用写返回类型
}
};
Point2D p2(p3);
10.函数运算符()的重载
仿函数,就是使一个类使用看上去像一个函数
class Pow
{
public:
Pow() {}
int operator ()(int i)
{
return i * i;
}
};
int main()
{
Pow pow;
int i = 4;
cout << pow(i)<< endl; //按常理来说应该是pow()i,系统为了美观变成pow(i)
return 0;
}
11.堆内存操作符的重载(new delete)
格式如下
重点:可以在new中实现自我的早期定制而不用使用构造函数,详细内容见例6。
例6. 堆内存运算符的重载
#include <iostream>
#include <string.h>
using namespace std;
class A
{
public:
A()
{
cout<<"A()"<<endl;
}
~A()
{
cout<<"~A()"<<endl;
}
void func()
{
cout<<"void func()"<<endl;
}
void* operator new(size_t size)
{
cout<<"size = "<<size<<endl;
cout<<"void* operator new(size_t size)"<<endl;
void *p = malloc(size);
memset(p,0,size);
return p;
}
void operator delete(void *p)
{
cout<<"void operator delete(void *p)"<<endl;
free(p);
}
void *operator new[](size_t size)
{
cout<<"size = "<<size<<endl;
cout<<"void *operator new[](size_t size)"<<endl;
void *p = malloc(size);
memset(p,0,size);
((A*)p)->data = 100; //可以实现自我早期定制,不用使用构造器
return p;
}
void operator delete[](void *p)
{
cout<<"void operator delete[](void *p)"<<endl;
free(p);
}
double data;
};
int main()
{
A* p = new A;
p->func();
cout<<p->data<<endl;
delete p;
// A* p = new A[5];
// p->func();
// delete []p;
// int *p = new int;
return 0;
}
12.智能指针的重载
智能指针:
auto_ptr<A> ptr(new A); //auto_ptr 类模板 auto_ptr<A>模板类
要实现智能指针的重载,建立一个类,利用类对象成员退出栈空间的析构函数来实现自动delete
#include <iostream>
#include <string.h>
#include <memory>
using namespace std;
class A
{
public:
A()
{
cout<<"A()"<<endl;
}
~A()
{
cout<<"~A()"<<endl;
}
void func()
{
cout<<"void func()"<<endl;
}
};
class Smt
{
public:
Smt(A *p)
{
ptr = p;
}
~Smt()
{
delete ptr;
}
A*& operator->()
{
return ptr;
}
A& operator*()
{
return *ptr;
}
A *ptr;
};
void foo()
{
// auto_ptr<A> ptr(new A); //auto_ptr 类模板 auto_ptr<A>模板类
//new A被ptr托管以后,不需要再关心delete的问题。delete在ptr离开其栈空间时发生
// ptr->func();
// (*ptr).func();
Smt smt(new A); //模拟智能指针自动delete
(*smt).func();
// smt->func();
// (smt.ptr)->func();
}
int main()
{
foo();
return 0;
}
13.++的重载
前置++的重载
在默认++的运算中有以下计算规则
int main()
{
int a = 100;
int b = ++a;
cout<<a<<" "<<b<<endl;
++++a;
cout<<a<<endl;
}
所以可得重载函数为
Complex& Complex::operator ++()
{
this->_x++;
this->_y++;
return *this;
}
后置++的重载
计算规则
int main()
{
int a = 100; //能通过
int b = a++; //能通过
a++++; //无法通过
cout<<a<<" "<<b<<endl;
}
由于a++++无法通过,所以返回值类型为const型,因为const类型无法调用非const函数
在选择返回类型是否为引用时,原则是能使用引用尽量使用引用。
为了区分前++和后++,在后++的重载函数调用参数中加 int ,如果为全局的,函数调用参数为(complex &,int)