目錄
一、運算符重載基本概念
運算符重載,就是對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型。
|
語法:
|
二、運算符重載碰上友元函數
友元函數是一個全局函數,和我們上例寫的全局函數類似,只是友元函數可以訪問某個類私有數據。
案例: 重載左移操作符(<<),使得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;
}
八、符號重載總結
- =, [], () 和 -> 操作符只能通過成員函數進行重載
- << 和 >>只能通過全局函數配合友元函數進行重載
- 不要重載 && 和 || 操作符,因爲無法實現短路規則
常規建議: