C++自修入門實境秀、C++ Primer 5版研讀秀 28/ ~4.11. Type Conversions 型別轉換-20190812_17...





頁159

4.11. Type Conversions

18:10

When Implicit Conversions Occur

In most expressions, values of integral types smaller than int are first promoted to an appropriate larger integral type. 18:40

24:30

4.11.1. The Arithmetic Conversions

算術型別的轉換原則是小的型別會轉成最大的型別

頁160

27:00

Integral Promotions 整數升等 整數提升

The types bool, char, signed char, unsigned char, short, and unsigned short are promoted to int if all possible values of that type fit in an int. Otherwise, the value is promoted to unsigned int.

33:40

Operands of Unsigned Type 無號型別運算元

40:20 given要翻成「某一個」或「有一個」在漢語才貼切精準

46:15所以前面在安排我們了解sizeof這個得知型別大小的運算子。現在在這裡談到型別轉換,就和型別彼此的大小息息相關了。

1:0:10

If the long type has more bits, then the unsigned int will be converted to long .

如果long型別有更多的位元,那麼unsigned int會被轉 為 long °

has more bits,是什麼意思?

Understanding the Arithmetic Conversions

頁161

1:26:00

練習4.34

1:37:00



float fval = 0;

double dval = 0;

int ival = 0; char cval = 'a';

auto f=dval + ival * cval;



/*(a) if (fval)//if fval =0 then fval=false,else fval=true;

(b)dval = fval + ival;//求精確度ival會先轉成float,加法結果指定給dval時再轉成double

(c)dval + ival * cval; *///cval先整數提升(integral promotion)為int,然後和ival相乘,再轉成double與dval相加

練習4.35

1:44:19 1:57:55

char cval='a'; int ival=2; unsigned int ui=1;

float fval=1.1; double dval=1.13;

//identify the implicit type conversions, if any, taking place :

//(a)cval = 'a' + 3;//cval、'a'均整數提昇為int

//(b)fval = ui - ival * 1.0;//ival轉成float*1.0 float和int sizeof 同為4,而ui為unsigned所以是由機器決定

//(c)dval = ui * fval;//也是由機器決定,看ui與fval誰大誰小

//(d)cval = ival + fval + dval;//ival + fval先轉成float +dval時再轉成double,指定給=cval時,再

//cval會先整數提升(integral promotion)成int,右邊運算出來的

//double結果則被truncate(截斷)成整數,再指定給cval

4.11.2. Other Implicit Conversions

Array to Pointer Conversions

This conversion is not performed when an array is used with decltype or as the operand of the address-of (&), sizeof, or typeid (which we’ll cover in § 19.2.2 (p. 826)) operators. The conversion is also omitted when we initialize a reference to an array (§ 3.5.1, p. 114). As we’ll see in § 6.7 (p. 247), a similar pointer conversion happens when we use a function type in an expression.

陣列轉指標,在下列情況不會發生:

1.decltype同用時

2.作為以下運算子的運算元時:

(1)&

(2)sizeof

(3)typeid

3.將一個參考初始化給一個陣列時。(就是用陣列將一個參考到陣列的參考初始化,陣列作為initializer(初始器)) 參詳頁115 2:14:00

頁162

2:18:18

Pointer Conversions

指標轉換(指標的型別轉換)

void*

2:30:00

Conversions to bool:

轉成布林值bool值

算術與指標(pointer)型別都會自動轉換成布林值

唯有值0轉成布林值false,餘均為true

2:32:58

Conversion to const:

2:26:20

指向非常值的指標可以轉換成指向常值的指標

We can convert a pointer to a nonconst type to a pointer to the corresponding const type, and similarly for references.

考你「to」是誰的 不見題目只見關鍵字 convert …… to……

error: conversion from const to nonconst not allowed

由「變」轉「常」可,由「常」轉「變」不可

證成法身佛,就是常,不可能再退位為無常的凡夫!

我們薄地凡夫觀心無常,固是「變」,可藉此「假」「變」之身修證成「真」「常」佛陀

low-level const

低階的const

前面是翻成低層、高層(見頁64)



Conversions Defined by Class Types

由類別型別(class type)定義的型別轉換

類別型別所定義的轉換



If the last attempt failed, then the conversion to bool yields false.

如果上一次的嘗試失敗,那麼對bool的轉換就會 產出alse。

last在此應該是翻成最後一次吧?該不會是先用機器翻譯殘留下來的痕跡?

3:2:03

4.11.3. Explicit Conversions

明確轉型用「case」(鑄型、重鑄、重塑)

頁163

To do so, we’d need a way to explicitly convert i and/or j to double . We

要那麼做,我們需要一種方式明確地把i和j轉為double。

中文版這裡沒有把and/or的語意完整翻出。

這是說只轉一個i或j也可,或同時轉i和j。因為只轉i,則double和int的運算依然會被隱含轉型給轉換

3:9:00

Named Casts 具名的強制轉型

3:10:00

參考一定是左值(lvalue)

cast-name < type >( expression );

The cast-name may be one of static_cast, dynamic_cast, const_cast, and reinterpret_cast.



3:25:10

當型別不清楚時,想要指定型別,就需要用上cast了

we can use a static_cast to retrieve a pointer value that was stored in a void* pointer (§ 2.3.2, p. 56):

我們可以使用一個 static_cast來取回之前儲存在一個void*指標(§2.3.2)中的指標值:

static_cast

ok: address of any non const object can be stored in a void*

任何一個非常值的物件,其位址都可以存在型別為void*的指標(pointer)

3:30:00

和型別有關的都會用上角括弧<>,如對vector變數的宣告及定義亦然



const_cast

3:35:55

A const_cast changes only a low-level (§ 2.4.3 , p. 63 ) const in its operand:

可見與static_cast相反:

other than those involving low-level const

const_cast是專門對low-level-const重塑(cast)的

頁164

casts away the const



const char *pc;

char *p = const_cast<char*>(pc); // ok: but writing through p is undefined

// ok :但透過p寫入的行為是未定義的

3:58:00未定義的(undefined)不等於會出錯,只是結果無法捉摸,得自行負責!在以下測試例中,常數cc值在區域變數視窗中會被改變成98 'b' 但在印出cc值的結果中,卻仍是a\97!且程式不會出錯:

const char cc = 'a'; char c = 'b';

const char* pc=&cc;

char* p = const_cast<char*>(pc);

*p = c;

cout << cc << endl;

printf("%i\n",cc);

似乎未定義的(undefined)就是不確定的、沒必然性的……



Only a const_cast may be used to change the constness of an expression.

只有const_cast可用來變更一個運算式的常數性質(constness)。

所以const_cast是對const的cast,不是對型別(type)的cast:

we cannot use a const_cast to change the type of an expression:

const_cast only changes constness

4:13:50

reinterpret_cast 重解鑄型(cast)

重解,就是把原來的型別重新解讀,可以看作類似「別名」的作用。所以這裡雖然是:

int *ip;

char *pc = reinterpret_cast<char*>(ip);

不見題目只見關鍵字 看到reinterpret,就要注意,他不是真的轉型成為char*,而是仍然保留int*(就是ip原來的型別),只是換個面目或裝扮(只是換裝)來表現而已。

否則,明明「char *pc」的意思是指向char的指標,怎麼會變成在對int值的定址呢?(像未轉型前的ip那樣)

string str(pc);//即string str=pc;或string str{pc};

所以才會說「因此,以pc初始化str是絕對正確的」:

因此,以pc初始化str是絕對正確的,雖然在此例中是沒有意義或 可能導致更糟結果的!

Thus, the initialization of str with pc is absolutely correct—albeit in this case meaningless or worse!

這句是承前句「The compiler has no way of knowing that it actually holds a pointer to an int.」所以這裡的「absolutely correct」也是編譯器認為的。因為它沒法兒知道,pc它實際上並不是指向char的指標,而是指向int的的指標

int i = 97;

int* ip(&i);

char* cp = reinterpret_cast<char*>(ip);

string str{ cp };

cout << str << '\t' << cp << '\t'<<*ip<<endl;

上倒中cp解不解參考,印出來的都是「a」!

4:46:00 4:56:40

頁165

Old-Style Casts

舊式的重鑄(cast)轉型

5:11:10 舊式的強制轉型(重鑄(cast))不像具名的Named Casts分4類,而是只有一種形式,二種表示法:

type (expr); // function-style cast notation

(type) expr; // C-language-style cast notation

一個是將運算式括起來,一個是將type括起來

對於具名的,只要是const_cast和static_cast可以運用上的地方,舊式的就是類似它倆的運作。若二者都不可通,那舊式的就自動轉為reinterpret_cast。





4:59:18

Advice: Avoid Casts 述而不作

建議:避免強制轉型

不要自我作聖



5:22:55

練習4.36

cast就像在優先權與結合性中的圓括號(),具有指名強制執行我們想要的行為與效果

const int ci = 97;

int i = ci;

double d = 3.341;

//i *= (int)d; //Old-Stye cast 1

//i *= int(d); //Old-Stye cast 2

i *= static_cast<int>(d);//named cast

//可見static在這裡 找對主詞 是什麼東東static 是說const不變的static

//所以它相對的就是const_cast,就是要變動const。因為轉型(重鑄(cast))本來就是要

//變動type,怎麼可能型別不動呢,唯有cosnt的動與不動了。

cout << i << '\t' << ci << '\t'<<d<<endl;



練習4.37

Rewrite each of the following old-style casts to use a named cast:

可見named cast 與 old-style cast 相對,而

const_cast則與static_cast相對。二者皆不通時,才用reinterpret_cast。

const string myname = "孫守真任真甫"; char cc = 'q';

int i = 11; double d = 3.14; const string* cps{&myname};

char* pc(&cc); void* pv = {&d};

//pv = (void*)cps;//old-style cast

//(a)pv = (void*)ps;

//string* ps= const_cast<string*>(cps);//先 casts away the const first

//pv = static_cast<void*>(ps);//named cast

//(b)i = int(*pc);

//i = int(*pc);//old-style cast

//i = static_cast<int>(*pc);

//(c)pv = &d;

//pv = static_cast<void*>(&d);//此非old-style cast(因都沒()括弧),這只是隱含轉型

//pc = (char*)pv;//old-style cast

pc = static_cast<char*>(pv);

//(d)pc = (char*)pv;

6:17:00

練習4.38

int i=10, j = 3;

double slope = static_cast<double>(j/ i);

j/i仍是int,所以會truncate 小數部分,此例slope的結果是將「j/i」的「0」值,轉換成「0.000……」的double,沒有意義!

頁166-167

4.12. Operator Precedence Table

Table 4.4. Operator Precedence

頁168

Chapter Summary

留言

熱門文章