国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

c++教程(二十二:Type conversions)

2019-11-11 01:42:19
字體:
供稿:網(wǎng)友

————————————————————————

該系列教程為翻譯c++官方教程,點擊參考英文原版,水平有限,翻譯不通之處敬請諒解!

————————————————————————

隱式轉(zhuǎn)換

當將值復制到兼容類型時,將自動執(zhí)行隱式轉(zhuǎn)換。例如:

short a=2000;int b;b=a;

在這里,a的值被從short轉(zhuǎn)換到int而沒有任何明確的操作。這就是所謂的標準轉(zhuǎn)換。標準轉(zhuǎn)換的影響基本數(shù)據(jù)類型,并允許數(shù)值類型之間的轉(zhuǎn)換(short到int,int到float,double到int…),或從bool,和一些指針的轉(zhuǎn)換。

從一些較小的整數(shù)類型轉(zhuǎn)換為int,或從float到double稱為擴展(PRomotion),保證在目的類型產(chǎn)生完全相同的值。其他算術(shù)類型之間的轉(zhuǎn)換并不總是能夠準確地表示相同的值:

(1)如果一個負整數(shù)的值轉(zhuǎn)換為無符號類型,所產(chǎn)生的值相當于其補數(shù)表示。(即,-1成為表示該類型的最大值,-2是第二大,…)。 (2)bool類型轉(zhuǎn)換例如flase,就可以相當于零(對于數(shù)值類型)或者空指針(指針類型);true相當于所有其他的值轉(zhuǎn)換為等效的1。 (3)如果轉(zhuǎn)換是從浮點類型到整型,則值被截斷(小數(shù)部分被刪除)。如果結(jié)果超出表示值類型范圍,則導致未定義的行為。 (4)否則,如果轉(zhuǎn)換介于同類型(int到int或float到float)的數(shù)值類型之間,則轉(zhuǎn)換是有效的,但值是具體實現(xiàn)的(并且可能不可移植)。

這些轉(zhuǎn)換可能意味著精度的損失,編譯器可能發(fā)出警告信號。這個警告可以避免轉(zhuǎn)換。

對于非基本類型,數(shù)組和函數(shù)隱式地轉(zhuǎn)換為指針,而指針一般允許下列轉(zhuǎn)換: (1)空指針可以轉(zhuǎn)換為任何類型的指針 (2)指向任何類型的指針可以轉(zhuǎn)換為空指針。 (3)指針向上:一個派生類指針可以轉(zhuǎn)換為一個accessible 和unambiguous 基類的指針,而無需修改其const或volatile的屬性。

隱式類轉(zhuǎn)換

在類的世界里,隱式轉(zhuǎn)換可以通過三個成員函數(shù)來控制: (1)單參數(shù)構(gòu)造函數(shù):允許從特定類型的隱式轉(zhuǎn)換初始化對象。 (2)賦值運算符:允許在賦值時從特定類型允許隱式轉(zhuǎn)換。 (3)類型轉(zhuǎn)換運算符:允許隱式轉(zhuǎn)換為特定類型。

例如:

// implicit conversion of classes:#include <iostream>using namespace std;class A {};class B {public: // conversion from A (constructor): B (const A& x) {} // conversion from A (assignment): B& Operator= (const A& x) {return *this;} // conversion to A (type-cast operator) operator A() {return A();}};int main (){ A foo; B bar = foo; // calls constructor bar = foo; // calls assignment foo = bar; // calls type-cast operator return 0;}

類型轉(zhuǎn)換運算符使用特定語法:它使用運算符關(guān)鍵字后跟目標類型和空括號集。注意,返回類型是目標類型,因此在運算符關(guān)鍵字之前沒有指定。

關(guān)鍵詞顯示

在一個函數(shù)調(diào)用中,C++允許隱式轉(zhuǎn)換發(fā)生在每個參數(shù)中。這對于某些類可能是有些問題的,因為它并不總是它想做的。例如,如果我們在最后一個例子中添加下面的函數(shù):

void fn (B arg) {}

這個函數(shù)需要類型B的參數(shù),但它也可以用類型A的對象作為參數(shù)調(diào)用:

fn (foo);

這可能是或可能不是想要實現(xiàn)的。但是,在任何情況下,可以通過顯式關(guān)鍵字標記受影響的構(gòu)造函數(shù)來防止:

// explicit:#include <iostream>using namespace std;class A {};class B {public: explicit B (const A& x) {} B& operator= (const A& x) {return *this;} operator A() {return A();}};void fn (B x) {}int main (){ A foo; B bar (foo); bar = foo; foo = bar;// fn (foo); // not allowed for explicit ctor. fn (bar); return 0;}

此外,顯式標記的構(gòu)造函數(shù)不能用賦值語法來調(diào)用;在上面的示例中,不能用:

B bar = foo;

類型的成員函數(shù)(上一節(jié)中描述的)也可以被指定為顯式。這可以防止與目標類型的顯式指定構(gòu)造函數(shù)一樣的隱式轉(zhuǎn)換。

強制類型轉(zhuǎn)換

C++是強類型語言。許多的轉(zhuǎn)換,特別是那些隱含的值不同的解釋,需要顯式轉(zhuǎn)換,在C++中稱為type-casting。有兩種通用type-casting主要語法:functional 和c-like:

double x = 10.3;int y;y = int (x); // functional notationy = (int) x; // c-like cast notation

這些通用類型的強制轉(zhuǎn)換功能是足以滿足基本數(shù)據(jù)類型的大多數(shù)需求。然而,這些操作符可以套用在類和類的指針,從而導致代碼在語法正確但是會導致運行時錯誤的情況。例如,下面的代碼沒有編譯錯誤:

// class type-casting#include <iostream>using namespace std;class Dummy { double i,j;};class Addition { int x,y; public: Addition (int a, int b) { x=a; y=b; } int result() { return x+y;}};int main () { Dummy d; Addition * padd; padd = (Addition*) &d; cout << padd->result(); return 0;}

程序聲明了一個指向加法的指針,但是它使用顯式類型賦值將它分配給另一個無關(guān)類型的對象的引用:

padd = (Addition*) &d;

不受限制的顯式類型轉(zhuǎn)換允許將任何指針轉(zhuǎn)換為其他指針類型,而獨立于它們指向的類型。對成員結(jié)果的后續(xù)調(diào)用將產(chǎn)生運行時錯誤或其他一些意想不到的結(jié)果。

為了控制這些類型之間的相互轉(zhuǎn)換的類,我們有四個具體的casting 操作: dynamic_cast,reinterpret_cast,static_cast和const_cast。它們的格式是按照新類型的括號括在角度括號之間,然后在括號之間轉(zhuǎn)換表達式。

dynamic_cast <new_type> (expression)reinterpret_cast <new_type> (expression)static_cast <new_type> (expression)const_cast <new_type> (expression)

傳統(tǒng)類型type-casting 等價于這些表達式將:

(new_type) expressionnew_type (expression)

但每一個有其特殊的特點:

dynamic_cast

dynamic_cast只能使用指針和引用的類(或void *)。其目的是確保類型轉(zhuǎn)換的結(jié)果指向目標指針類型的有效完整對象。

這自然包括 pointer upcast(從指針的指針轉(zhuǎn)換指針的基源),同樣允許隱式轉(zhuǎn)換。

但dynamic_cast也可以downcast,(將指針指向派生基地)多態(tài)類(那些虛擬成員)當且僅當指向的對象是一個有效的完整的目標對象類型。例如:

// dynamic_cast#include <iostream>#include <exception>using namespace std;class Base { virtual void dummy() {} };class Derived: public Base { int a; };int main () { try { Base * pba = new Derived; Base * pbb = new Base; Derived * pd; pd = dynamic_cast<Derived*>(pba); if (pd==0) cout << "Null pointer on first type-cast./n"; pd = dynamic_cast<Derived*>(pbb); if (pd==0) cout << "Null pointer on second type-cast./n"; } catch (exception& e) {cout << "Exception: " << e.what();} return 0;}

兼容性注意:這種類型的dynamic_cast需要運行時類型信息(RTTI)跟蹤動態(tài)類型。一些編譯器支持此功能作為默認禁用的選項。這需要運行時進行類型檢查使得dynamic_cast與這些類型能正常工作。

上面的代碼試圖執(zhí)行從類型 base*指針的對象動態(tài)模型(PBA和PBB)到另一種指針類型Derived*派生的對象的兩種dynamic_cast,但只有第一個是成功的。注意各自的初始化:

Base * pba = new Derived;Base * pbb = new Base;

雖然都是類型base*指針,PBA其實指向類型派生的對象,而pbb 指向的是Base類型。因此,當各自的類型轉(zhuǎn)換都進行dynamic_cast,pba 是指向一個完整的對象派生類Derived,而pbb 是指向基類Base的對象,這是一個不完整的對象派生類。

當dynamic_cast不能使用指針因為它不是一個完整的對象所需的類,而在前面的例子中第二轉(zhuǎn)換,它返回一個空指針來表明是失敗的。dynamic_cast用來轉(zhuǎn)換為引用類型的轉(zhuǎn)換是不可能的,反而是bad_cast拋出的異常類型。

dynamic_cast也可以允許在指針中執(zhí)行其他隱式強制轉(zhuǎn)換:casting 之間的指針類型的空指針(即使在不相關(guān)的類中),和casting 任何指針任何類型void*指針。

static_cast

static_cast能在指針之間的相互轉(zhuǎn)換相關(guān)的類,不僅upcasts(從pointer-to-derived到pointer-to-base),而且downcasts 強制類型轉(zhuǎn)換(從pointer-to-base到pointer-to-derived)。在運行時不執(zhí)行檢查,以確保正在轉(zhuǎn)換的對象實際上是目標類型的完整對象。因此,它是由程序 員來確保轉(zhuǎn)換是安全的。另一方面,它不承擔對dynamic_cast類型安全檢查的開銷。

class Base {};class Derived: public Base {};Base * a = new Base;Derived * b = static_cast<Derived*>(a);

這是有效的代碼,雖然b指向的類的一個對象的引用,如果不完全,還可能導致運行時錯誤。 因此,static_cast能夠執(zhí)行類的指針不僅可以隱式轉(zhuǎn)換,而且其相反的轉(zhuǎn)換。

static_cast也能夠執(zhí)行所有的轉(zhuǎn)換允許隱式(不只是那些類的指針),也能完成這些相反的。它可以: (1)從void*轉(zhuǎn)換為任何指針類型。在這種情況下,它保證如果從相同的指針類型轉(zhuǎn)換為void*值,得到的指針值是相同的。 (2)轉(zhuǎn)換為整數(shù),浮點值和枚舉類型的枚舉類型。

此外,static_cast還可以執(zhí)行以下: (1)顯式調(diào)用單個參數(shù)構(gòu)造函數(shù)或轉(zhuǎn)換運算符。 (2)轉(zhuǎn)換為右值引用。 (3)將枚舉類的值轉(zhuǎn)換為整數(shù)或浮點值。 (4)將任何類型轉(zhuǎn)換為void,評估和丟棄這個值。

reinterpret_cast

reinterpret_cast是轉(zhuǎn)換任何指針類型的任何其他類型的指針,甚至不相關(guān)的類。操作結(jié)果是從一個指針到另一個指針的簡單二進制復制。允許所有指針轉(zhuǎn)換:既不指向指針的內(nèi)容,也不檢查指針類型本身。 它也可以將指針轉(zhuǎn)換為整數(shù)類型。該整數(shù)值表示指針的格式是環(huán)境所特定的。唯一可以肯定的是,指針轉(zhuǎn)換到一個大到足以完全包含它的整數(shù)類型(如intptr_t),保證可以追溯到一個有效的指針。 可以由reinterpret_cast但不能由static_cast轉(zhuǎn)換的類型的二進制表示是低級操作的轉(zhuǎn)換,這在大多數(shù)情況下,結(jié)果是系統(tǒng)特定的代碼,因而非便攜式。例如:

class A { /* ... */ };class B { /* ... */ };A * a = new A;B * b = reinterpret_cast<B*>(a);

編譯這個代碼,雖然它沒有多大意義,因為現(xiàn)在b指向一個完全不相關(guān)和可能不相容類的對象。引用b是不安全的。

const_cast

這類casting 操縱對象所指的常量指針,或者被設(shè)置或者被刪除。例如,為了通過const函數(shù)的指針,預設(shè)為非const參數(shù):

// const_cast#include <iostream>using namespace std;void print (char * str){ cout << str << '/n';}int main () { const char * c = "sample text"; print ( const_cast<char *> (c) ); return 0;}

上面的例子保證工作,因為函數(shù)print 不向指針對象寫入。需要注意的是,這消除指針對象從而寫入它導致未定義的行為。

typeid

typeid 可以用于到檢查的表達式的類型:

typeid (expression)

這個操作符返回一個在標準頭文件typeinfo中定義的到一個對象類型的type_info型類型信息。typeid返回的值可以與另一個typeid操作符==和!= 對比,或者可以得到一個空終止字符序列,利用其name()成員表示數(shù)據(jù)類型或類的名字。

// typeid#include <iostream>#include <typeinfo>using namespace std;int main () { int * a,b; a=0; b=0; if (typeid(a) != typeid(b)) { cout << "a and b are of different types:/n"; cout << "a is: " << typeid(a).name() << '/n'; cout << "b is: " << typeid(b).name() << '/n'; } return 0;}結(jié)果為a and b are of different types:a is: int *b is: int

當typeid應(yīng)用于類,typeid使用RTTI來跟蹤動態(tài)對象的類型。當typeid用于表達式的類型是類的多態(tài)性,結(jié)果是大部分來自完整的對象類型:

// typeid, polymorphic class#include <iostream>#include <typeinfo>#include <exception>using namespace std;class Base { virtual void f(){} };class Derived : public Base {};int main () { try { Base* a = new Base; Base* b = new Derived; cout << "a is: " << typeid(a).name() << '/n'; cout << "b is: " << typeid(b).name() << '/n'; cout << "*a is: " << typeid(*a).name() << '/n'; cout << "*b is: " << typeid(*b).name() << '/n'; } catch (exception& e) { cout << "Exception: " << e.what() << '/n'; } return 0;}

注意:type_info成員的name字符串返回的名稱取決于你的編譯器和庫的具體實現(xiàn)。它不一定是一個具有典型類型名稱的簡單字符串,就像在編譯器中用來生成這個輸出一樣。

注意typeid認為指針的類型是指針類型本身(A和B的類型都是class Base )。然而,當typeid用于對象(如*a和 b)typeid得到的就是的動態(tài)類型(即他們的大部分來自完整的對象類型)。

如果typeid測試的類型是在解引用操作符(*)前的指針,這個指針有一個空值,那么typeid拋出一個異常bad_typeid。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 乌拉特前旗| 潜江市| 郑州市| 临武县| 会同县| 和平县| 名山县| 浮山县| 苍梧县| 板桥市| 大宁县| 舒城县| 什邡市| 靖西县| 图们市| 株洲市| 黄平县| 城口县| 辰溪县| 阿勒泰市| 静宁县| 怀化市| 淳化县| 漳平市| 镇康县| 环江| 铁力市| 开封县| 通州市| 九龙县| 景洪市| 和田市| 巨野县| 金平| 宣威市| 新安县| 武胜县| 衡水市| 婺源县| 宜都市| 乾安县|