1. 程式人生 > >【c/c++】型別轉換函式(型別轉換運算子過載函式)

【c/c++】型別轉換函式(型別轉換運算子過載函式)

轉換建構函式可以將一個指定型別的資料轉換為類的物件。但是不能反過來將一個類的物件轉換為一個其他型別的資料(例如將一個Complex類物件轉換成double型別資料)。在C++提供型別轉換函式(type conversion function)來解決這個問題。型別轉換函式的作用是將一個類的物件轉換成另一型別的資料。

如果已聲明瞭一個Complex類,可以在Complex類中這樣定義型別轉換函式:

    operator double( )
    {
        return real;
    }
函式返回double型變數real的值。它的作用是將一個Complex類物件轉換為一個double型資料,其值是Complex類中的資料成員real的值。請注意,函式名是operator double,這點是和運算子過載時的規律一致的(在定義運算子“+”的過載函式時,函式名是operator +)。

型別轉換函式的一般形式為:
    operator 型別名( )
    {
        實現轉換的語句
    }
在函式名前面不能指定函式型別,函式沒有引數。其返回值的型別是由函式名中指定的型別名來確定的。型別轉換函式只能作為成員函式,因為轉換的主體是本類的物件。不能作為友元函式或普通函式。


從函式形式可以看到,它與運算子過載函式相似,都是用關鍵字operator開頭,只是被過載的是型別名。double型別經過過載後,除了原有的含義外,還獲得新的含義(將一個Complex類物件轉換為double型別資料,並指定了轉換方法)。這樣,編譯系統不僅能識別原有的double型資料,而且還會把Complex類物件作為double型資料處理。

那麼程式中的Complex類對具有雙重身份,既是Complex類物件,又可作為double型別資料。Complex類物件只有在需要時才進行轉換,要根據表示式的上下文來決定。轉換建構函式和型別轉換運算子有一個共同的功能:當需要的時候,編譯系統會自動呼叫這些函式,建立一個無名的臨時物件(或臨時變數)。

一定要注意這裡是只有在需要的時候,只有在需要的時候才會去呼叫。


使用型別轉換函式的簡單例子。

#include <iostream>
using namespace std;
class Complex
{
public:
   Complex( ){real=0;imag=0;}
   Complex(double r,double i){real=r;imag=i;}
   operator double( ) {return real;} //型別轉換函式
private:
   double real;
   double imag;
};

int main( )
{
   Complex c1(3,4),c2(5,-10),c3;
   double d;
   d=2.5+c1;//要求將一個double資料與Complex類資料相加
   cout<<d<<endl;
   return 0;
}
輸出結果:

5.5

對程式的分析:

1) 如果在Complex類中沒有定義型別轉換函式operator double,程式編譯將出錯。

因為不能實現double 型資料與Complex類物件的相加。現在,已定義了成員函式 operator double,就可以利用它將Complex類物件轉換為double型資料。請注意,程式中不必顯式地呼叫型別轉換函式,它是自動被呼叫的,即隱式呼叫。

在什麼情況下呼叫型別轉換函式呢?編譯系統在處理表達式 2.5 +cl 時,發現運算子“+”的左側是double型資料,而右側是Complex類物件,又無運算子“+”過載函式,不能直接相加,編譯系統發現有對double的過載函式,因此呼叫這個函式,返回一個double型資料,然後與2.5相加。


2) 如果在main函式中加一個語句:
    c3=c2;
請問此時編譯系統是把c2按Complex類物件處理呢,還是按double型資料處理?由於賦值號兩側都是同一類的資料,是可以合法進行賦值的,沒有必要把c2轉換為double型資料。

3) 如果在Complex類中聲明瞭過載運算子“+”函式作為友元函式:
    Complex operator+ (Complex c1,Complex c2)//定義運算子“+”過載函式
    {
        return Complex(c1.real+c2.real, c1.imag+c2.imag);
    }
若在main函式中有語句
    c3=c1+c2;
由於已對運算子“+”過載,使之能用於兩個Complex類物件的相加,因此將c1和c2按Complex類物件處理,相加後賦值給同類物件c3。如果改為
    d=c1+c2; //d為double型變數
將c1與c2兩個類物件相加,得到一個臨時的Complex類物件,由於它不能賦值給double型變數,而又有對double的過載函式,於是呼叫此函式,把臨時類物件轉換為double資料,然後賦給d。

從前面的介紹可知,對型別的過載和對運算子的過載的概念和方法都是相似的,過載函式都使用關鍵字operator。因此,通常把型別轉換函式也稱為型別轉換運算子函式,由於它也是過載函式,因此也稱為型別轉換運算子過載函式(或稱強制型別轉換運算子過載函式)。

假如程式中需要對一個Complex類物件和一個double型變數進行+,-,*,/等算術運算,以及關係運算和邏輯運算,如果不用型別轉換函式,就要對多種運算子進行過載,以便能進行各種運算。這樣,是十分麻煩的,工作量較大,程式顯得冗長。如果用型別轉換函式對double進行過載(使Complex類物件轉換為double型資料),就不必對各種運算子進行過載,因為Complex類物件可以被自動地轉換為double型資料,而標準型別的資料的運算,是可以使用系統提供的各種運算子的。

包含轉換建構函式、運算子過載函式和型別轉換函式的程式。

先閱讀以下程式,在這個程式中只包含轉換建構函式和運算子過載函式。

#include <iostream>
using namespace std;
class Complex
{
public:
	Complex(){ real = 0; imag = 0; }  //預設建構函式
	Complex(double r){ real = r; imag = 0; }//轉換建構函式
	Complex(double r, double i){ real = r; imag = i; }//實現初始化的建構函式
	friend Complex operator + (Complex c1, Complex c2); //過載運算子“+”的友元函式
	void display();
private:
	double real;
	double imag;
};
Complex operator + (Complex c1, Complex c2)//定義運算子“+”過載函式
{
	return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
void Complex::display()
{
	cout << "(" << real << "," << imag << "i)" << endl;
}
int main()
{
	Complex c1(3, 4), c2(5, -10), c3;
	c3 = c1 + 2.5; //複數與double資料相加
	c3.display();
	return 0;
}

輸出的結果為:

(5.5,4i)

對程式的分析:
1) 如果沒有定義轉換建構函式,則此程式編譯出錯。

2) 現在,在類Complex中定義了轉換建構函式,並具體規定了怎樣構成一個複數。由於已過載了算符“+”,在處理表達式c1+2.5時,編譯系統把它解釋為
    operator+(c1, 2.5)
由於2.5不是Complex類物件,系統先呼叫轉換建構函式Complex(2.5),建立一個臨時的Complex類物件,其值為(2.5+0i)。上面的函式呼叫相當於
    operator+(c1, Complex(2.5))
將c1與(2.5+0i) 相加,賦給c3。執行結果為
    (5.5+4i)
3) 如果把“c3=c1+2.5;”改為c3=2.5+c1; 程式可以通過編譯和正常執行。過程與前相同。

從中得到一個重要結論,在已定義了相應的轉換建構函式情況下,將運算子“+”函式過載為友元函式,在進行兩個複數相加時,可以用交換律。

如果運算子函式過載為成員函式,它的第一個引數必須是本類的物件。當第一個運算元不是類物件時,不能將運算子函式過載為成員函式。如果將運算子“+”函式過載為類的成員函式,交換律不適用。

由於這個原因,一般情況下將雙目運算子函式過載為友元函式。單目運算子則多過載為成員函式。

這個和我們之前學過的所謂實參和傳參的型別必須一致是一個道理,只不過這裡就是更加的明確了,仔細了而已


4) 如果一定要將運算子函式過載為成員函式,而第一個運算元又不是類物件時,只有一個辦法能夠解決,再過載一個運算子“+”函式,其第一個引數為double型。當然此函式只能是友元函式,函式原型為
    friend operator+(double, Complex &);
顯然這樣做不太方便,還是將雙目運算子函式過載為友元函式方便些。

5) 在上面程式的基礎上增加型別轉換函式:
    operator double( ){return real;}
此時Complex類的公用部分為:
   public:
   Complex( ){real=0;imag=0;}
   Complex(double r){real=r;imag=0;}  //轉換建構函式
   Complex(double r,double i){real=r;imag=i;}
   operator double( ){return real;}//型別轉換函式
   friend Complex operator+ (Complex c1,Complex c2); //過載運算子“+”
   void display( );

其餘部分不變。程式在編譯時出錯,原因是出現二義性。

當類中出現了轉換建構函式和型別轉換函式的時候,必須要注意是否會出現二義性的問題

相關推薦

C++類和物件.四個預設成員函式賦值運算子過載

1.(1)類的定義   類就是具有相同資料和相同操作的一組物件的集合。 學生類定義: class student {//成員變數char* name;int age;int sex;//成員函式void speak(){cout<<name<<"年

AI實戰快速掌握TensorFlow三):激勵函式

到現在我們已經瞭解了TensorFlow的特點和基本操作(見文章:快速掌握TensorFlow(一)),以及TensorFlow計算圖、會話的操作(見文章:快速掌握TensorFlow(二)),接下來我們將繼續學習掌握TensorFlow。 本文主要是學習掌握TensorFlow的激勵函式

AI實戰快速掌握TensorFlow四):損失函式

在前面的文章中,我們已經學習了TensorFlow激勵函式的操作使用方法(見文章:快速掌握TensorFlow(三)),今天我們將繼續學習TensorFlow。 本文主要是學習掌握TensorFlow的損失函式。 一、什麼是損失函式 損失函式(loss function)是機器學習

c++虛擬函式override)和過載函式overload)的比較

1. 過載函式要求函式有相同的函式名稱,並有不同的引數序列;而虛擬函式則要求完全相同; 2. 過載函式可以是成員函式或友元函式,而虛擬函式只能是成員函式; 3. 過載函式的呼叫是以所傳遞引數的差別作為呼叫不同函式的依據,虛擬函式是根據物件動態型別的不同去呼叫不同

C++ 複製建構函式和賦值運算子過載函式

宣告一個空的類testsize,sizeof(testsize)為1,為其宣告建構函式和解構函式,依舊為1 建構函式不能使用關鍵字virtual,解構函式可以 一旦類中存在虛擬函式,就會為該類生成虛擬函式表,並在每一個例項中新增一個指向虛擬函式表的指標,從而大小為一個指標大

類String的建構函式、拷貝建構函式、解構函式和賦值運算子過載函式的實現

#include <iostream> using namespace std; class String { public: String(const char* str= NULL); String(const String& other); ~

c/c++型別轉換函式型別轉換運算子過載函式)

用轉換建構函式可以將一個指定型別的資料轉換為類的物件。但是不能反過來將一個類的物件轉換為一個其他型別的資料(例如將一個Complex類物件轉換成double型別資料)。在C++提供型別轉換函式(type conversion function)來解決這個問題。型別轉換函式的

資料結構棧的應用--數制轉換c++)

標頭檔案: #pragma once #include <iostream> #include <assert.h> using namespace std; template<class Type> class SeqStack

C++C++類的學習三)——運算子過載與友元函式

前言       前面的兩篇博文中介紹了類的一些基本特性,今天講一講運算子過載和友元。運算子過載      運算子過載是C++中一種形式的多型,運算子過載將過載的概念運用到運算子上,賦予運算子更多地含義。也許乍然一聽,似乎我們對它並不熟悉,其實它一直為我們使用,例如 * 運算

入門篇Nginx + FastCGI 程序C/C++) 搭建高性能web service的Demo及部署發布

框架 logs ice term con scrip 什麽 5.1 cal 由於最近工作的需要,本人學習了一下利用高性能web server - Nginx,來發布C/C++編寫的fastCGI程序,詳細細節如下。 1.介紹 Nginx - 高性能w

C#圖解PictureBox.SizeMode 屬性轉)

img attach mage 圖解 auto deb ict cmm src PictureBoxSizeMode.Normal: 默認情況下,在 Normal 模式中,Image 置於 PictureBox 的左上角,凡是因過大而不適合 PictureBox 的任何

C++11unoedered_map和map部分轉載)

好的 hash 比較 綜合 per 百萬 一點 應該 .net 1.結論 新版的hash_map都是unordered_map了,這裏只說unordered_map和map. 運行效率:unordered_map最高,而map效率較低但提供了穩定效率和有序的序列。 占用內存

C#/WPF圖像數據格式轉換時,透明度丟失的問題

csdn pypi 數據類型 acc scan str 圖像 ber release 原文:【C#/WPF】圖像數據格式轉換時,透明度丟失的問題 問題:工作中涉及到圖像的數據類型轉換,經常轉著轉著

10、C++ STL容器適配器stack queue priority_queue)

pub function 適配 pty str 成員 cto ali The 容器適配器   stack、queue、priority_queue 都不支持任一種叠代器,它們都是容器適配器類型,stack是用vector/deque/list對象創建了一個先進後出容器;qu

C語言實現一個計算器兩種方式)

1.使用switch…case…語句實現 #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> #include <stdlib.h> int add(int x, int y) {   &nb

C語言typedef(自定義資料型別)與#define(巨集定義)用法比較

  不管是在C語言還是在C++中,typedef這個詞都不少見,當然出現頻率較高的還是在C程式碼中。typedef和#define有些相似,但更多的是不同,特別是在一些複雜的用法上,就完全不同了。      1.巨集定義(#define)      巨集定義又稱為巨集代換

C語言巨集定義define 和型別重新命名typedef

  C語言裡面有兩個不容易區分的語法概念,巨集定義define 和型別重新命名typedef。下面我們來談一下兩者之間的差異。   1.型別重新命名typedef: 關鍵字typedef提供了一種為已定義好的資料型別建立別名的機制,為了建立更簡短的型別名,通常使用type

C++String類String查詢單個字元,查詢字串的函式實現

#include<iostream> #include<stdlib.h> #include<assert.h> using namespace std; class String { public:     String(const c

遞歸執行過程探究c

ase 部分 函數賦值 自己的 cto tdi tro 地方 inpu c語言 遞歸的執行過程探究 引用《c primer plus》第五版 9.3.1 遞歸的使用 1 /* recur.c -- recursion illustration */ 2 #incl

C#MVC搭建.netMVC4工程四)錯誤詳解-ErrorGeneratingOutput

遇到一個問題,不知道各位有沒有遇到過。在網上搜索沒有中文的解決方案。 問題描述: 解決辦法:在你的系統變數中找到名為VS120COMNTOOLS的變數: 去你們本地的資料夾(每個人根據安裝目錄不一致,可能不太一樣),你會發現在指向的目錄下沒有錯