C++中operator的两种用法
首先聲明,轉載自:http://blog.csdn.net/skdkjzz/article/details/45872801
?
轉換函數的名稱是類型轉換的目標類型,因此,不必再為它指定返回值類型;轉換函數是被用于本類型的數值或變量轉換為其他的類型,也不必帶參數
?
在寫這篇文章之前,讓我們先回顧一下編譯器通過匹配過程確定調用哪一個函數的匹配順序:
(1)尋找和使用最符合函數名和參數類型(包括返回值)的函數,若找到則調用;
(2)否則,尋找一個函數模板,將其實例化產生一個匹配的重載函數,若找到則調用;
(3)否則,尋找可以通過類型轉換進行參數匹配的重載函數,若找到則調用它。
如果以上步驟均未找到匹配函數,則這個調用是錯誤的;如果這個調用有多于一個的匹配選譯,則調用匹配出現二義性,也是錯誤的。
??
類型轉換是將一種類型的值映射為另一種類型的值。類型轉換實際上包含有自動隱含和強制的兩種。
C語言編譯系統提供的內部數據類型的自動隱式轉換規則如下:
1.程序在執行算術運算時,低類型可以轉換為高類型。
2.在賦值表達式中,右邊表達式的值自動隱式轉換為左邊變量的類型,并賦值給它。
3.當在函數調用時,將實參值賦給形參,系統隱式地將實參轉換為形參的類型后,賦給形參。
4.函數有返回值時,系統將自動地將返回表達式類型轉換為函數類型后,賦值給調用函數。
在以上情況下,系統會進行隱式轉換的。當在程序中發現兩個數據類型不相容時,又不能自動完成隱式轉換,則將出現編譯錯誤。例如:
int* p = 100;
在這種情況下,編譯程序將報錯,為了消除錯誤,可以進行如下所示的強制類型轉換:
int* p = (int *)100;?
將整型數100顯式地轉換成指針類型。
構造函數具有類型轉換功能
在實際應用中,當類定義中提供了單個參數的構造函數時,該類便提供了一種將其他數據類型的數值或變量轉換為用戶所定義數據類型的方法。因此,可以說單個參數的構造函數提供了數據轉換的功能。下面通過一個例子進一步說明單參數構造函數的類型轉換功能。
代碼如下:
class A { public:A(){ m=0; } A(doublei) { m=i; } void print() { cout<<M<<endl} private:double m; };void main() {A a(5); a=10; //a與10是不同的數據類型a.print(); }
程序的輸出結果為:
10
在該程序中,賦值語句a=10;中,賦值號兩邊數值10和對象a是兩上不相容的數據類型,可是它卻能順利通過編譯程序,并且輸出顯示正確結果,其主要原因是得益于單參數的構造函數。編譯系統選通過標準數據類型轉換,將整型數值10轉換成double型,然后,再通過類中定義的單參數構造函數將double型數值轉換為A類類型,最后把它賦值給a。這些轉換都是自動隱式完成的。
關于上面的程序,補充一點:
Aa = 10;?
和
Aa;?
a= 10;?
兩者是不同的,前者對a進行初使化,編譯器會嘗試將10隱式轉換為A類型,這樣將引起a的A(doublei)構造函數直接被調用。
后者屬于賦值語句,編譯器將建立一個臨時對象,并將10隱式轉換為A類型。如果我們顯示調用
(A)10;
這也將建立一個臨時對象,引起A的構造函數被調用。
還有一點要注意,編譯器只會進行一次隱式轉換(C時刻庫的內置類型如intshort char等)除外,下面的語句說明了這點:
m_rst->GetFields()->GetItem(nCol)->Value= (_bstr_t)sValue;?
上面Value是COM的變體類型,“Value=”將引起operator= (_bstr_t)被調用。如果上面省略(_bstr_t),編譯器將發生錯誤,因為沒有operator= (char*)這樣的重載,編譯器不會為我們進行兩次以上的隱式轉換。
在函數調用過程中,運算符重載和構造也是一個函數調用,如果匹配的函數如無二義性,那么將可以產生一次隱式轉換。如果上句的Value變體類只有一個operate= (_bstr_t),那么既使這樣寫->Value= sValue; 編譯器也會試圖將sValue隱式轉換為_bstr_t類型。
還有一種情況
代碼如下:
classA?
{
? ? int a;?
public:
? ? A(){ };?
? ? A(int_a) { a = _a; };?
? ? Operator int() { return a; }?
}
有如下調用:
代碼如下:
A a(10);?
A a2 = (int)(int)a;?? //只相當于Aa2 = (int)a; 因為第一個就近已經轉成了int,第二//個就不用再轉了
比較有意思吧,A類既有將int隱式轉換A的構造,也有int()轉換函數供強制轉換,(int)(int)a將以就近原則的方式進行。如果就近轉換失敗,編譯器將報錯。比如:
代碼如下:
classB?
{
};
A a2 = (B)a;?
或
A a2 = (B)10;?
編譯器報這樣的錯誤:"errorC2440: “類型轉換”:無法從“int”轉換為“B”"
可知,我們自己編寫的構造和轉換函數多么重要。
轉換函數
轉換函數又稱類型強制轉換成員函數,它是類中的一個非靜態成員函數。它的定義格式如下:
代碼如下:
class<類型說明符1>
{
public:
operator<類型說明符2>();
…
}
這個轉換函數定義了由<類型說明符1>到<類型說明符2>之間的映射關系??梢?#xff0c;轉換函數是用來將一種類型的數據轉換成為另一種類型。下面通過一個例子說明轉換函數的功能。
代碼如下:
?
#includeclass Rational { public:Rational(intd, int n) {den= d; num= n; }operator double();//類型轉換函數 private:int den, num; };Rational::operator double() {return double(den)/double(num); }void main() {Rational r(5, 8); double d = 4.7; d += r; //這句將調用隱式轉換,相當于d= (double)r; cout<<d<<ENDL; }程序輸出結果:
5.325
?
由程序可知,d是一個double型數值,r是Rational類的對象,這兩個不同類型的數據進行加法之所以能夠進行是得益于轉換函數operatordouble()。為使上述加法能夠進行,編譯系統先檢查類Rational的說明,看是否存在在下轉換函數能夠將Rational類型的操作數轉換為double類型的操作數。由于Rational類中說明了轉換函數operatordouble(),它可以在程序運行時進行上述類型轉換,因此,該程序中實現了d=r;的操作。
定義轉換函數時應注意如下幾點:
(1)轉換函數是用戶定義的成員函數,但它要是非靜態的。
(2)轉換函數的不可以有返回值。(意思是聲明中不可以有返回值)
(3)轉換函數也不帶任何參數。
(4)轉換函數函數還不能定義為友元函數。
轉換函數的名稱是類型轉換的目標類型,因此,不必再為它指定返回值類型;轉換函數是被用于本類型的數值或變量轉換為其他的類型,也不必帶參數。
類中的構造函數完成其他類型到類類型的轉換,而重載強制轉換完成類類型到其他類型的轉換。
?
1.??operator 用于類型轉換函數:
類型轉換函數的特征:
1)??型轉換函數定義在源類中;
2)??須由 operator 修飾,函數名稱是目標類型名或目標類名;
3)??函數沒有參數,沒有返回值,但是有return
語句,在return語句中返回目標類型數據或調用目標類的構造函數。
類型轉換函數主要有兩類:
1)??對象向基本數據類型轉換:
對象向不同類的對象的轉換:
例程1:
//通過類型轉換函數求半徑為5的圓的面積 //并將其存儲在float型變量中打印輸出 #include <iostream> using namespace std; class CArea {float area; public:CArea(){area=0;}CArea(float a) //重載含有一個參數的構造函數{area=a;}void getArea(){cout<<area<<endl;}void setArea(float a){area=a;}operator float() //類型轉換函數{ //將面積類對象轉換為float型數據return area;} }; class CCircle {float R; public:void getR(){cout<<R<<endl;}void setR(float r){R=r;}operator CArea() //類型轉換函數{ //將圓類對象轉為面積類對象float area=3.1415926*R*R;return (CArea(area));} }; void main() {CCircle cir;CArea are;float a;cir.setR(5);cir.getR(); //打印圓的半徑are.getArea(); //打印轉換前的面積 are=cir; //將圓類對象轉為面積類對象are.getArea(); //打印轉換后的面積 a=are; //將面積類對象轉換為float型數據cout<<a<<endl; } //將面積類對象轉換為float型數據return area;} }; class CCircle {float R; public:void getR(){cout<<R<<endl;}void setR(float r){R=r;}operator CArea() //類型轉換函數{ //將圓類對象轉為面積類對象float area=3.1415926*R*R;return (CArea(area));} }; void main() {CCircle cir;CArea are;float a;cir.setR(5);cir.getR(); //打印圓的半徑are.getArea(); //打印轉換前的面積 are=cir; //將圓類對象轉為面積類對象are.getArea(); //打印轉換后的面積 a=are; //將面積類對象轉換為float型數據cout<<a<<endl; }?
?
2.??operator 用于操作符重載:
操作符重載的概念:
????
??將現有操作符與一個成員函數相關聯,并將該操作符與其成員對象(操作數)一起使用。
注意事項:
1)??重載不能改變操作符的基本功能,以及該操作符的優先級順序。
2)??重載不應改變操作符的本來含義。
3)??只能對已有的操作符進行重載,而不能重載新符號。
4)??操作符重載只對類可用。
5)??以下運算符不能被重載:
.???????原點操作符(成員訪問符)
*?????指向成員的指針
::???????作用域解析符
? :?????問號條件運算符
sizeof 操作數的字節數
???操作符函數的一般格式:
???????????????return_type operator op(argument list);
??????return_type:返回類型(要得到什么)
????????op:要重載的操作符
??????argument list:參數列表(操作數有哪些)
例程2:
//重載大于號操作符比較兩個人的工資 #include <iostream> using namespace std; class employee {int salary; public:void setSalary(int s){salary=s;}void getSalary(){cout<<salary<<endl;}bool operator >(const employee & e)//重載大于號操作符{if(salary > e.salary)return true;elsereturn false;} }; void main() {employee emp1,emp2;emp1.setSalary(1000);emp2.setSalary(2000);if (emp1 > emp2){cout<<"emp1比emp2工資高"<<endl;}else{cout<<"emlp1沒有emp2工資高"<<endl;} }?
?
聲明:operator XX(); 無返回值,XX就是某個類型;
用法:XX a = (XX)obj; 假設上邊SocketAddress非abstract類,例如:SocketAddress sa; int a = (socklen_t)sa; 也就是此時會調用原成員函數operator XX(); 一般返回XX類型值,可以理解成類型轉換的重載!
另外:一個自定義類的 構造函數可以用作隱形的類型轉換,
例如:Class A { A(int i) { val = i}; ?private int val;} , A a = 5;?
解:5 首先通過構造函數A(int)隱形的轉換為A類型,然后調用默認的operator=賦值函數,賦值給a;
總結
以上是生活随笔為你收集整理的C++中operator的两种用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 积分图像
- 下一篇: Opencv中Mat的data数据只定义