4、1 基礎
4.1.1 基本概念
1、左值和右值
(1)C++的表達式要不然是右值(rvalue),要不然就是左值(lvalue)
(2)一個重要原則:在需要右值的地方可以用左值來替代,但不能把右值當成左值使用(有一種情況例外,可以把右值當成左值使用)。
(3)當一個對象被用作右值的時候,用的對象的值(内容),當對象被用作左值的時候,用的是對象的身份(在記憶體中的位置)
(4)需要用到左值的運算符
①指派運算符(需要一個非常量左值)
②取位址符
③内置解引用運算符、下标運算符。
④内置類型和疊代器的遞增減運算符
4.1.2 優先級與結合律
1、複合表達式(compound expression):是指含有兩個或多個運算符的表達式。
(1)括号可以無視優先級和結合律。
4.1.3 求值順序
1、有四種運算符明确規定了運算符對象的求值順序
(1)&&
(2)||
(3)?:
(4),
4.3節練習
4.10:為while循環寫一個條件,使其從标準輸入中讀取整數,遇到42時候停止。
int a;
while (cin >> a&&a != )
cout << a << endl;
4.11:書寫一條表達式用于測試4個值a、b、c、d的關系,確定a大于b、b大于c、c大于d
int a = , b = , c = , d = ;
if (a > b&&b > c&&c > d)
cout << "a>b,b>c,c>d" << endl;
4.4 指派運算符
1、指派運算符滿足右結合律
2、指派運算表達式優先級比較低,是以在條件語句中,指派部分通常應該加上括号。
4.5 遞增和遞減運算符
1、
(1)前置版本(++i):先将運算對象加(減1),然後将改變後的對象作為求值結果。
(2)後置版本(i++):先将對象作為求值結果,再給運算對象加1(或減1)
2、運算對象可按任意順序求值
4.7條件運算符
1、格式:
(1)condition為真,執行expr1
(2)condition為假,執行expr2
2、條件運算符可嵌套
3、條件運算符的優先級非常低,是以當一條長表達式中嵌套了(?:),通常需在兩端加上括号。
4、7節練習
4.21:編寫一段程式,使用條件運算符從vector中找到哪些元素的值是奇數,然後将這些奇數值
int a;
std::vector<int> iv;
while(cin>>a)
iv.push_back(a);
for(auto:vi)
cout<<((i%==)?:i*);
4.22:用條件運算符版本将學生成績分為fail、low pass、pass、high pass四個階層。
int grade;
cout<<"Enter grade:\n";
cin>>grade;
cout<<(grade<?"fail":(grade<?"low pass":(grade<?"pass":"high pass")))<<endl;
用if語句寫的版本
int grade;
cout<<"Enter grade: ";
cin>>grade;
if(grade<)
cout<<"fail"<<endl;
else if(grade<&&grade>)
cout<<"low pass"<<endl;
else if(grade>&&grade<)
cout<<"pass"<<endl;
else
cout<<"high pass"<<endl;
4.8 位運算符
1、位運算符作用于整數類型的運算對象,并把運算對象看成是二進制的集合。
(1)位運算符提供檢查和設定二進制位的功能
2、bitset類型,其标準庫類型也可以表示任意大小的二進制位集合。
3、位運算符(滿足左結合律)
(1)~(位求反)
<1>格式:
~expr
(2)<<(左移) >>(右移)
<1>格式:
expr1<<expr2
expr1>>expr2
(3)&(位與)
<1>格式:
expr1&expr2
(4)^(位異或)
<1>格式:
expr^expr
(5)|(位與)
<1>格式:
expr|expr
4、位運算符(又叫IO運算符)滿足左結合律
4.9 sizeof運算符
1、作用:傳回一條表達式或一個類型名所占的位元組數
2、格式:
(1)
sizeof (type);
size expr;
3、sizeof運算符可擷取類成員大小而無須提供一個具體的對象。
4.11 類型轉換 ##
1、隐式轉換(implicit conversion):由編譯器自動執行的類型轉換(自動執行,無須程式員介入。)
2、發生隐式轉換的情況
(1)比int類型小的整型值受限提升為較大的整數類型
(2)在條件中,非布爾值轉換成布爾類型
(3)初始化過程中,初始值(literal)轉換成變量類型
(4)指派語句中,右側運算符轉換成左側運算符
(5)算術運算符或關系運算符有多種類型的時候
(6)函數調用的時候
4.11.3 顯式轉換
1、命名的強制類型轉換(cast)
(1)格式: cast-name(expression)
<1>type:轉換的目标類型
<2>expression:要轉換的值
<3>type若是引用類型,則結果是左值
<4>cast-name是以下4種類型
①static_const
②dynamic_cast
③const_cast
④reinterpret_cast
中的一種
(2)static_cast:任何具有明确定義的類型轉換,隻要不包含底層const,都可以使用。
<1>例:
double slope=static_cast<double>(j)/i;
<2>優點:較大算術類型轉換為較小算術類型。
(3)const_cast:隻能改變運算對象的底層const
<1>例:
const char c='k';
char *pc=&c;
char *p=const_cast<char *>(pc);
//正确,但是通過p寫值是未定義的行為
<2>優點:const_cast能去掉底層const,将一個指向常量的指針轉換為一個指向不一定是常量的指針。
(4)reinterpret_cast:通常為運算對象的位模式提供較低層次上的重新解釋(一般用于不同類型的指針轉換)
<1>例:
int *ip;
char *pc=reinterpret_cast<char *>ip;
//pc所指向的對象為int而非字元
string str(pc); //運作時發生錯誤
2、舊式的強制類型轉換
(1)格式:
type(expr); //函數形式的強制類型轉換
(type)expr; //C風格的強制類型轉換
4.11.3節練習
4.36:假設i是int類型,d是double類型,書寫表達式i*=d使其執行整數類型的乘法而非浮點類型的乘法
int i=;
double d=;
i*=static_cast<double>(d);
i*=d;
cout<<i<<endl;
4.37:用命名的強制類型轉換改寫下列舊式的轉換語句
int i;
double d;
const string *ps;
char *pc;void *pv;
(a)pv=(void *)ps;
pv=static_cast<void *>(const_cast<string *>(ps));
(b)i=int(*pc);
i=static_cast<int>(*pc);
(c)pv=&d;
pv=static_cast<void *>(&d);
(d)pc=(char *)pv;
pc=static_cast<char *>(pv);