標籤:
1.頌值電訊廠商
首先來福值運算子引入後面要說的運算子多載。上一節說了建構函式、拷貝建構函式;一個類要想進行更好的控制。須要定義自己的建構函式、拷貝建構函式、解構函式、當然,還有賦值運算子。常說的三大函數就是指拷貝、賦值、析構。
假設一個類不定義自己的賦值運算子。會自己產生一個預設的賦值運算操作。這個預設的賦值運算滿足一般類的需求。它實現的是一個淺拷貝。可是當類的功能、作用逐漸完好時,就會出現非常多問題。所以,通過自己定義賦值運算子來控制賦值操作時類的行為是非常有必要的。當一個類的對象與對象之間發生賦值(=)運算時,就會調用重載的賦值運算子函數。
還是以上節的範例來說。看代碼:
#include <iostream>#include <new>#include <string>using namespace std;class Person{public:Person();Person(int n, const string &str);Person(const Person &n);Person &operator=(const Person &p);//賦值運算子函數~Person();private:int age;string *name;};Person::Person():age(0), name(NULL){cout << "Default Person" << endl;}Person::Person(int n, const string &str):age(n), name(new string(str)){cout << "Init Person" << endl;}Person::Person(const Person &n){if(n.name){name = new string(*(n.name));age = n.age;}else{name = NULL;age = 0;}}Person & Person::operator=(const Person &p){if(this == &p){return *this;//推斷傳入的對象是否是當前對象本身}string *tmp = new string(*p.name);//又一次分配一段空間delete this->name;//釋放原空間this->name = tmp;this->age = p.age;return *this;}Person::~Person(){cout << "~Person " << "name: " << name << " age: " << age << endl;delete name;}int main(){Person p1(20, "SCOTT");Person p2;p2 = p1;return 0;}
在這裡,假設沒有自己定義賦值運算子,當執行P2 = P1時,是沒有錯的。而錯誤會處在析構部分,上一篇文章中已經說明原因。
Init Person
Default Person
~Person name: 0x8264020 age: 20
~Person name: 0x8264020 age: 20
Segmentation fault (core dumped)——段錯誤!
自己定義賦值運算子之後。執行結果例如以下:
Init Person
Default Person
~Person name: 0x8121030 age: 20
~Person name: 0x8121020 age: 20
注意:
1)一般來說,大多數賦值運算子函數組合了解構函式和拷貝建構函式的工作。
2)假設講一個對象賦予它自身。賦值運算子必須能正確的工作。
3)當編寫賦值運算子函數時。一個好的模式是將右側對象複製到一個局部暫時對象中。拷貝完畢後,銷毀左側對象的現有成員就是安全的了。
然後將資料從暫時對象複製到左側對象。
2.運算子多載
上面是眾多運算子多載的一個執行個體。重載的運算子是具有特殊名字的函數:它們的名字是由keywordoperator和其後要定義的運算子號共同組成。
它與普通函數一樣也有返回值、參數列表、以及函數體。
重載運算子函數的參數數量與該運算子的作用的運算對象數量一樣多。一元運算子有一個參數。二元運算子有兩個。
對於二元運算子來說,左側運算對象傳遞給第一個參數,右側運算對象傳遞給第二個參數。
假設一個運算子函數是成員函數,則它的第一個(左側)運算對象綁定到隱式的this指標上。因此,成員運算子函數的參數比運算子的運算對象少一個。(如上例中的=運算子)
2.1 輸入、輸出運算子
IO標準庫分別使用>>和<<運行輸入和輸出操作。
類能夠按須要來自己定義輸入、輸出運算子。
範例:
#include <iostream>#include <new>#include <string>using namespace std;class Person{public:Person();Person(int n, const string &str);Person(const Person &n);Person &operator=(const Person &p);~Person();string getName()const;friend ostream &operator<<(ostream &out, const Person &p);//輸出運算子friend istream &operator>>(istream &in, Person &p);//輸入運算子private:int age;string *name;};Person::Person():age(0), name(NULL){cout << "Default Person" << endl;}Person::Person(int n, const string &str):age(n), name(new string(str)){cout << "Init Person" << endl;}Person::Person(const Person &n){if(n.name){name = new string(*(n.name));age = n.age;}else{name = NULL;age = 0;}}Person & Person::operator=(const Person &p){if(this == &p){return *this;}string *tmp = new string(*p.name);delete this->name;this->name = tmp;this->age = p.age;cout << "operator =" << endl;return *this;}Person::~Person(){cout << "~Person " << "name: " << name << " age: " << age << endl;delete name;}string Person::getName()const{if(name){return *name;}return string();}//重載輸出運算子ostream &operator<<(ostream &out, const Person &p){out << "p.age: " << p.age << ", p.name: " << p.getName();return out;}//重載輸入運算子istream &operator>>(istream &in, Person &p){string s;cout << "please input age and name:";in >> p.age >> s;if(in)//推斷是否讀取正確{p.name = new string(s);}else{p = Person();}return in;}int main(){Person p1(20, "SCOTT");Person p2(10, "Kate");Person p3;/*cout << p1 << endl;cout << p2 << endl;cout << p3 << endl;*/cin >> p3;cout << p3 << endl;return 0;}
執行程式,輸入12 Mike, 結果例如以下:
Init Person
Init Person
Default Person
please input age and name:12 Mike
p.age: 12, p.name: Mike
~Person name: 0x939a088 age: 12
~Person name: 0x939a048 age: 10
~Person name: 0x939a020 age: 20
總結:
1.輸入、輸出運算子必須是非成員函數。
2.輸入、輸出運算子一般聲明為友元類型。
3.輸出運算子函數中第二個參數能夠聲明為const型,由於不須要改變其值。而輸入運算子的第二個參數不能為const,由於它要接受輸入。另外,返回值最好是引用,避免了值拷貝過程。
著作權聲明:本文部落格原創文章,部落格,未經同意,不得轉載。
C++ Primer筆記10_運算子多載_賦值運算子_進入/輸出操作符