目录
一、运算符重载基本概念
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
|
语法:
|
二、运算符重载碰上友元函数
友元函数是一个全局函数,和我们上例写的全局函数类似,只是友元函数可以访问某个类私有数据。
案例: 重载左移操作符(<<),使得cout可以输出对象。
class Person{
friend ostream& operator<<(ostream& os, Person& person);
public:
Person(int id,int age){
mID = id;
mAge = age;
}
private:
int mID;
int mAge;
};
ostream& operator<<(ostream& os, Person& person){
os << "ID:" << person.mID << " Age:" << person.mAge;
return os;
}
int main(){
Person person(1001, 30);
//cout << person; //cout.operator+(person)
cout << person << " | " << endl;
return EXIT_SUCCESS;
}
三、可重载的运算符
几乎C中所有的运算符都可以重载,但运算符重载的使用时相当受限制的。特别是不能使用C中当前没有意义的运算符(例如用**求幂)不能改变运算符优先级,不能改变运算符的参数个数。这样的限制有意义,否则,所有这些行为产生的运算符只会混淆而不是澄清寓语意。
四、自增自减(++/--)运算符重载
例如当编译器看到++a(前置++),它就调用operator++(a),当编译器看到a++(后置++),它就会去调用operator++(a,int).
class MyInter
{
friend ostream& operator<<(ostream & cout, MyInter myInt);
public:
MyInter()
{
num = 0;
}
//重载递增运算符
//前置
MyInter& operator++()
{
//先++
num++;
//后返回自身
return *this;
}
//后置 如果在形参中添加int占位参数,编译器可以识别出这是后置++
MyInter operator++(int)
{
//先 记录原来值
MyInter temp = *this;
//再 ++
num++;
//再将记录的值返回
return temp;
}
private:
int num;
};
//全局函数重载<<
ostream& operator<<( ostream & cout , MyInter myInt)
{
cout << myInt.num;
return cout;
}
//前置递增
void test01()
{
MyInter myInt;
cout << myInt << endl; // 0
cout << ++(++myInt) << endl; // 2
cout << myInt << endl; // 2
}
//后置递增
void test02()
{
MyInter myInt;
cout << myInt << endl; // 0
cout << myInt++ << endl; // 0
cout << myInt << endl; // 1
}
int main(){
test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
调用代码时候,要优先使用前缀形式,除非确实需要后缀形式返回的原值,前缀和后缀形式语义上是等价的,输入工作量也相当,只是效率经常会略高一些,由于前缀形式少创建了一个临时对象。 |
五、赋值(=)运算符重载
编译器会默认给一个类添加4个函数:
- 构造函数(空实现)
- 析构函数(空实现)
- 拷贝构造(值拷贝)
- operator= (值拷贝)
赋值符常常初学者的混淆。这是毫无疑问的,因为’=’在编程中是最基本的运算符,可以进行赋值操作,也能引起拷贝构造函数的调用。
class Person
{
public:
Person(){ cout << "Person默认构造函数调用" << endl; }
Person(const char * name) // "Tom"
{
cout << "Person有参构造函数调用" << endl;
this->m_Name = new char[strlen(name) + 1];
strcpy(this->m_Name ,name);
}
Person(const Person & p)
{
cout << "Person拷贝构造函数调用" << endl;
this->m_Name = new char[strlen(p.m_Name) + 1];
strcpy(this->m_Name, p.m_Name);
}
//重载 = 运算符
Person& operator=(const Person & p)
{
//先判断堆区是否有数据,如果有先释放干净
if (this->m_Name != NULL)
{
delete [] this->m_Name;
this->m_Name = NULL;
}
this->m_Name = new char[strlen(p.m_Name) + 1];
strcpy(this->m_Name, p.m_Name);
return *this;
}
~Person()
{
cout << "Person析构函数调用" << endl;
if (this->m_Name != NULL)
{
delete [] this->m_Name;
this->m_Name = NULL;
}
}
char * m_Name;
};
void test01()
{
Person p1("Tom");
Person p2("Jerry");
Person p3;
p3 = p1 = p2; //赋值
cout << "p1的姓名为: " << p1.m_Name << endl;
cout << "p2的姓名为: " << p2.m_Name << endl;
cout << "p3的姓名为: " << p3.m_Name << endl;
Person p4(p3);
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
六、等于和不等于(==、!=)运算符重载
class Complex{
public:
Complex(char* name,int id,int age){
this->pName = new char[strlen(name) + 1];
strcpy(this->pName, name);
this->mID = id;
this->mAge = age;
}
//重载==号操作符
bool operator==(const Complex& complex){
if (strcmp(this->pName,complex.pName) == 0 &&
this->mID == complex.mID &&
this->mAge == complex.mAge){
return true;
}
return false;
}
//重载!=操作符
bool operator!=(const Complex& complex){
if (strcmp(this->pName, complex.pName) != 0 ||
this->mID != complex.mID ||
this->mAge != complex.mAge){
return true;
}
return false;
}
~Complex(){
if (this->pName != NULL){
delete[] this->pName;
}
}
private:
char* pName;
int mID;
int mAge;
};
void test(){
Complex complex1("aaa", 10, 20);
Complex complex2("bbb", 10, 20);
if (complex1 == complex2){ cout << "相等!" << endl; }
if (complex1 != complex2){ cout << "不相等!" << endl; }
}
七、不要重载&&、||
不能重载operator&& 和 operator|| 的原因是:
无法在这两种情况下实现内置操作符的完整语义。
说得更具体一些,内置版本版本特殊之处在于:内置版本的&&和||首先计算左边的表达式,如果这完全能够决定结果,就无需计算右边的表达式了。而这种计算模式模式我们一般无法实现,所以不能重载。
我们说操作符重载其实是另一种形式的函数调用而已,对于函数调用总是在函数执行之前对所有参数进行求值。
class Complex{
public:
Complex(int flag){
this->flag = flag;
}
Complex& operator+=(Complex& complex){
this->flag = this->flag + complex.flag;
return *this;
}
bool operator&&(Complex& complex){
return this->flag && complex.flag;
}
public:
int flag;
};
int main(){
Complex complex1(0); //flag 0
Complex complex2(1); //flag 1
//原来情况,应该从左往右运算,左边为假,则退出运算,结果为假
//这边却是,先运算(complex1+complex2),导致,complex1的flag变为complex1+complex2的值, complex1.a = 1
// 1 && 1
//complex1.operator&&(complex1.operator+=(complex2))
if (complex1 && (complex1 += complex2)){
cout << "真!" << endl;
}
else{
cout << "假!" << endl;
}
return EXIT_SUCCESS;
}
八、符号重载总结
- =, [], () 和 -> 操作符只能通过成员函数进行重载
- << 和 >>只能通过全局函数配合友元函数进行重载
- 不要重载 && 和 || 操作符,因为无法实现短路规则
常规建议: