所谓重载,就是重新赋予新的含义。运算符重载就是赋予运算符新的含义(新功能),其本质是一个函数。
C++预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型是没办法操作的,此时就需要重载运算符来实现。
运算符函数定义的一般格式如下:
<返回类型说明符> operator <运算符符号>(<参数表>) { <函数体> } |
下面通过几个实例熟悉重载运算符的使用
#include using namespace std;
class Complex{ public: Complex(int a = 0, int b = 0){ this->a = a; this->b = b; } void print(){ cout << "a:b => " << a << ":" << b << endl; } public: int a; int b; };
Complex operator+(Complex &c1, Complex &c2){ Complex tmp(c1.a + c2.a, c1.b + c2.b); return tmp; }
void main(){ int a = 0, b = 0; int c = a + b; //1 基础类型编译器知道怎么做
//用户定义复杂类型需要用户重载运算符编译才知道怎么做 Complex c1(1, 2), c2(3, 4); Complex c3 = c1 + c2; c3.print();
system("pause"); return; } |
#include using namespace std;
class Complex{ public: Complex(int a = 0, int b = 0){ this->a = a; this->b = b; } void print(){ cout << a << " : " << b << endl; } public: //成员函数实现“-”运算符重载 Complex operator-(Complex &c2){ Complex tmp(this->a - c2.a, this->b - c2.b); return tmp; }
//前置-- Complex& operator--(){ this->a--; this->b--; return *this; } private: int a; int b; friend Complex operator+(Complex &c1, Complex &c2); friend Complex& operator++(Complex &c1); };
//友元函数(全局函数)“+”运算符重载 Complex operator+(Complex &c1, Complex &c2){ Complex tmp(c1.a + c2.a, c1.b + c2.b); return tmp; }
//前置++ Complex& operator++(Complex &c1){ c1.a++; c1.b++; return c1; }
void main() { Complex c1(1, 2), c2(3, 4); // 成员函数重载运算符 Complex c3 = c1 + c2; c3.print(); // 成员函数重载运算符 Complex c4 = c2 - c1; c4.print(); // 友元函数重载运算符 ++c1; c1.print(); // 友元函数重载运算符 --c1; c1.print(); system("pause"); return; } |
运行结果:
例2重载了单目运算符“++”和“--”,这两个运算符有两种使用方式,分别是前置和后置,例2只是实现了运算符之前功能的重载,那么运算符后置功能怎么重载呢?这就需要借助占位符来实现了,请看例子:
#include using namespace std;
class Complex{ public: Complex(int a = 0, int b = 0){ this->a = a; this->b = b; } void print(){ cout << a << " : " << b << endl; } public: //后置-- Complex operator--(int){ Complex tmp = *this; this->a--; this->b--; return tmp; } private: int a; int b; friend Complex operator++(Complex &c1, int); };
//后置++ Complex operator++(Complex &c1, int){ Complex tmp = c1; c1.a++; c1.b++; return tmp; // 由于是后置++,因此需要返回++前的对象 }
void main(){ Complex c1(1, 2);
// 友元函数重载运算符 c1++; c1.print();
// 友元函数重载运算符 c1--; c1.print();
system("pause"); return; } |
我们知道类的默认拷贝构造函数属于“浅拷贝”,这样就会导致在类实例化对象之间进行赋值操作时可能产生内存泄露问题,如:分别实例类对象obj1和obj2,当执行obj2=obj1时,obj2的指针就会指向obj1的内存空间,obj2原来内存空间泄露;另外当obj1删除时会释放对应的内存空间,而此时obj2指向的内存空间和obj1相同,当obj2删除时会再次释放同一个内存空间,造成内存泄露,因此我们需要重载“=”运算符来避免这个问题。
#include #include using namespace std;
class Student{ public: Student(const char *name, const int age){ int _len = strlen(name); m_name = (char *)malloc(_len + 1); // strcpy_s(m_name, _len+1, name); m_age = age; }
// Student obj2 = obj1; // 方法一:手工编写拷贝构造函数实现深copy Student(const Student& obj1){ int _len = strlen(obj1.m_name); m_name = (char *)malloc(_len + 1); strcpy_s(m_name, _len+1, obj1.m_name); m_age = obj1.m_age; }
// Student obj2 = obj1; // 方法二:重载等号操作符实现深copy Student& operator=(Student &obj1){ if (this->m_name != NULL){ delete[] m_name; m_age = 0; } this->m_name = new char[strlen(obj1.m_name) + 1]; strcpy_s(m_name, strlen(obj1.m_name)+1, obj1.m_name); this->m_age = obj1.m_age; return *this; }
~Student(){ if (m_name != NULL){ free(m_name); m_name = NULL; m_age = 0; } } protected: private: char *m_name; int m_age; };
//对象析构的时候 出现coredump void test() { Student obj1("xiaoming", 10); Student obj2 = obj1; //调用用户实现的拷贝构造函数,实现深拷贝 Student obj3("liming", 11); obj3 = obj1; // 等号操作符 obj1 = obj2 = obj3; // 需要返回引用 }
int main(){ test(); cout << "end..." << endl; system("pause"); return 0; } |
注意obj3 = obj1和obj1 = obj2 = obj3是不同的。当只是使用obj3 = obj1时,等号运算符重载函数返回元素和引用都可以;但是,如果要实现obj1 = obj2 = obj3功能,则必须返回引用,因为此时需要左值操作。
操作符“||”和“&&”内置实现了短路规则,而当重载这两个操作符是无法实现短路规则,导致函数中的参数都会被求值,无法达到预定效果,因此不要重载这两个运算符。
#include #include
using namespace std;
class Test{ public: Test(int i){ this->m_a = i; }
Test operator+ (const Test& obj){ Test ret(0);
ret.m_a = m_a + obj.m_a; return ret; }
bool operator&& (const Test& obj){ return m_a && obj.m_a; } private: int m_a; };
// && 从左向右 int main(){ int a1 = 0; int a2 = 1; if (a1 && (a1 + a2)){ cout << "a1,a2 结果为真..." << endl; }
Test t1 = 0; Test t2 = 1; if(t1 && (t1 + t2)){ cout << "t1,t2 结果为真..." << endl; } system("pause"); return 0; } |
当对以上代码正常情况我们会认为if(t1 && (t1 + t2))不会执行(t1+t2)因为前面t1已经为假了,但当对代码调试时,你会发现代码进入了(t1+t2)的过程,因此重载“&&”无法实现短路规则。
这里给一个实现自定义数组的实例,有助于熟悉重载运算符在实际项目中的使用。
myarray.h
#pragma once #include using namespace std;
class Array{ public: Array(int length); Array(const Array& obj); ~Array();
public: void setData(int index, int valude); int getData(int index); int length();
//函数返回值当左值,需要返回一个引用(元素本身) int& operator[](int i); //重载= Array& operator=(Array &a1); //重载 == bool operator==(Array &a1); //重载 != bool operator!=(Array &a1);
private: int m_length; int *m_space; }; |
myarray.cpp
#include "myarray.h"
Array::Array(int length) { if (length < 0){ length = 0; } m_length = length; m_space = new int[m_length]; }
//重写拷贝构造函数 Array::Array(const Array& obj){ this->m_length = obj.m_length; this->m_space = new int[this->m_length];
for (int i = 0; i this->m_space[i] = obj.m_space[i]; } } Array::~Array(){ if (m_space != NULL){ delete[] m_space; m_space = NULL; m_length = -1; } }
//a1.setData(i, i); void Array::setData(int index, int valude){ m_space[index] = valude; }
int Array::getData(int index){ return m_space[index]; }
int Array::length(){ return m_length; }
// a[i] = 1,因为要当左值使用,所以要返回引用 int& Array::operator[](int i){ return m_space[i]; }
//a2 = a1; Array& Array::operator=(Array &a1){ if (this->m_space != NULL){ delete[] m_space; m_length = 0; } m_length = a1.m_length; m_space = new int[m_length];
for (int i = 0; i m_space[i] = a1[i]; // 因为已经重载了[]操作符 } return *this; }
//if (a3 == a1) bool Array::operator==(Array &a1){ if (this->m_length != a1.m_length){ return false; }
for (int i = 0; i if (this->m_space[i] != a1[i]){ return false; } } return true; }
bool Array::operator!=(Array &a1){ return !(*this == a1); } |
Test.cpp
#include #include "myarray.h"
using namespace std;
int main(){ Array a1(10); { cout << "\na1: "; for (int i = 0; i a1.setData(i, i); a1[i] = i; // 调用[]操作符重载函数 } for (int i = 0; i cout << a1[i] << " "; } cout << endl; }
Array a2 = a1; { cout << "\na2: "; for (int i = 0; i cout << a2.getData(i) << " "; } cout << endl; }
Array a3(5); { a3 = a1; a3 = a2 = a1; cout << "\na3: "; for (int i = 0; i cout << a3[i] << " "; } cout << endl; } // ==和!= { if (a3 == a1) { printf("equality\n"); } else { printf("inequality\n"); }
if (a3 != a1) { printf("inequality\n"); } else { printf("equality\n"); } }
system("pause"); return 0; } |