C++基礎知識(四)—— 操作符/運算符

前面已經學習了變量和常量,我們可以開始對它們進行操作,這就要用到C++的操作符。有些語言,很多操作符都是一些關鍵字, 比如add, equals等等。C++的操作符主要是由符號組成的。這些符號不在字母表中,但是在所有鍵盤上都可以找到。這個特點使得C++程序更簡潔,也更國際化。運算符是C++語言的基礎,所以非常重要。

    你不需要背下所有這一小節的內容,這些細節知識僅供你以後需要時參考 。

賦值Assignation (=)

賦值運算符的功能是將一個值賦給一個變量。

a = 5;

將整數5賦給變量a。= 運算符左邊的部分叫做lvalue (left value),右邊的部分叫做rvalue (right value)。lvalue 必須是一個變量,而右邊的部分可以是一個常量,一個變量,一個運算(operation)的結果或是前面幾項的任意組合。

有必要強調賦值運算符永遠是將右邊的值賦給左邊,永遠不會反過來。

a = b;

將變量b (rvalue)的值賦給變量a (lvalue),不論a當時存儲的是什麼值。同時考慮到我們只是將b的數值賦給a,以後如果b的值改變了並不會影響到a的值.

例如:如果我們使用以下代碼(變量值的變化顯示在綠色註釋部分):

// 賦值符號例子

#include <iostream>
using namespace std;

int main ()
{
  int a, b;         // a:?,  b:?
  a = 10;           // a:10, b:?
  b = 4;            // a:10, b:4
  a = b;            // a:4,  b:4
  b = 7;            // a:4,  b:7

  cout << "a:";
  cout << a;
  cout << " b:";
  cout << b;

  return 0;
}
a:4 b:7               

以上代碼結果是a的值爲4, b的值爲7。最後一行中b的值被改變並不會影響到a,雖然在此之前我們聲明瞭a = b; (從右到左規則right-to-left rule)。

C++擁有而其他語言沒有的一個特性是賦值符 (=) 可以被用作另一個賦值符的rvalue (或rvalue的一部分) 。例如:

a = 2 + (b = 5);

等同於:

b = 5;
a = 2 + b;

它的意思是:先將5賦給變量b,然後把前面對b的賦值運算的結果(即5)加上2再賦給變量a,這樣最後a中的值爲7。因此,下面的表達式在C++中也是正確的:

a = b = c = 5; //將5同時賦給3個變量a, b和c。


數學運算符Arithmetic operators ( +, -, *, /, % )

C++語言支持的5種數學運算符爲:

  • + 加addition
  • - 減subtraction
  • * 乘multiplication
  • / 除division
  • % 取模module

加減乘除運算想必大家都很瞭解,它們和一般的數學運算符沒有區別。

唯一你可能不太熟悉的是用百分號(%)表示的取模運算(module)。取模運算是取兩個整數相除的餘數。例如,如果我們寫a = 11 % 3;,變量a的值將會爲結果2,因爲2是11除以3的餘數。


組合運算符Compound assignation operators (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)

C++以書寫簡練著稱的一大特色就是這些組合運算符compound assignation operators (+=, -=, *= 和 /= 及其他) ,這些運算符使得只用一個基本運算符就可改寫變量的值:

value += increase; 等同於 value = value + increase;

a -= 5; 等同於 a = a - 5;

a /= b; 等同於 a = a / b;

price *= units + 1; 等同於 price = price * (units + 1);

其他運算符以此類推。例如:

// 組合運算符例子

#include <iostream>
using namespace std;

int main ()
{
  int a, b=3;
  a = b;
  a+=2;             // 相當於 a=a+2
  cout << a;
  return 0;
}
5                  


遞增和遞減Increase and decrease

書寫簡練的另一個例子是遞增(increase)運算符 (++)和遞減(decrease) 運算符(--)。它們使得變量中存儲的值加1或減1。它們分別等同於+=1和-=1。因此:

a++;
a+=1;
a=a+1; 

在功能上全部等同,即全部使得變量a的值加1。

它的存在是因爲最早的C編譯器將以上三種表達式的編譯成不同的機器代碼,不同的機器代碼運行速度不一樣。現在,編譯器已經基本自動實行代碼優化,所以以上三種不同的表達方式編譯成的機器代碼在實際運行上已基本相同。

這個運算符的一個特點是它既可以被用作prefix前綴,也可以被用作後綴suffix,也就是說它既可以被寫在變量標識的前面(++a),也可以被寫在後面(a++)。雖然在簡單表達式如a++或++a中,這兩種寫法代表同樣的意思,但當遞增increase或遞減decrease的運算結果被直接用在其它的運算式中時,它們就代表非常不同的意思了:當遞增運算符被用作前綴prefix (++a) 時,變量a的值線增加,然後再計算整個表達式的值,因此增加後的值被用在了表達式的計算中;當它被用作後綴suffix (a++)時,變量a的值在表達式計算後才增加,因此a在增加前所存儲的值被用在了表達式的計算中。注意以下兩個例子的不同:

例 1 例 2
B=3;
A=++B;
// A 的值爲 4, B 
的值爲 4
B=3;
A=B++;
// A 
的值爲 3, B 的值爲 4

在第一個例子中,B在它的值被賦給A之前增加1。而在第二個例子中B原來的值3被賦給 A然後B的值才加1變爲4。


關係運算符Relational operators ( ==, !=, >, <, >=, <= )

我們用關係運算符來比較兩個表達式。如ANSI-C++ 標準中指出的,關係預算的結果是一個bool值,根據運算結果的不同,它的值只能是真truefalse

例如我們想通過比較兩個表達式來看它們是否相等或一個值是否比另一個的值大。以下爲C++的關係運算符:

== 相等Equal
!= 不等Different
> 大於Greater than
< 小於Less than
>= 大於等於Greater or equal than
<= 小於等於Less or equal than

下面你可以看到一些實際的例子:

(7 == 5) 將返回false.
(5 > 4) 將返回true.
(3 != 2) 將返回true.
(6 >= 6) 將返回true.
(5 < 5) 將返回false.

當然,除了使用數字常量,我們也可以使用任何有效表達式,包括變量。假設有a=2, b=3和c=6,

(a == 5) 將返回false.
(a*b >= c) 將返回true 因爲它實際是(2*3 >= 6)
(b+4 > a*c) 將返回false因爲它實際是(3+4 > 2*6)
((b=2) == a) 將返回true.

注意:運算符= (單個等號)不同於運算符== (雙等號)。第一個是賦值運算符(將等號右邊的表達式值賦給左邊的變量);第二個(==)是一個判斷等於的關係運算符,用來判斷運算符兩邊的表達式是否相等。因此在上面例子中最後一個表達式((b=2) == a),我們首先將數值2賦給變量b,然後把它和變量a進行比較。因爲變量a中存儲的也是數值2,所以整個運算的結果爲true。

在ANSI-C++標準出現之前的許多編譯器中,就像C語言中,關係運算並不返回值爲真true或假falsebool值,而是返回一個整型數值最爲結果,它的數值可以爲0,代表"false"或一個非0數值(通常爲1)來代表"true"。


邏輯運算符Logic operators ( !, &&, || )

運算符 ! 等同於boolean 運算NOT (取非),它只有一個操作數(operand),寫在它的右邊。它做的唯一工作就是取該操作數的反面值,也就是說如果操作數值爲真true,那麼運算後值變爲假false,如果操作數值爲假false,則運算結果爲真true。它就好像是說取與操作數相反的值。例如:

!(5 == 5) 返回false,因爲它右邊的表達式(5 == 5)爲真true.
!(6 <= 4) 返回true因爲(6 <= 4)爲假false.
!true 返回假false.
!false 返回真true.

邏輯運算符&&和||是用來計算兩個表達式而獲得一個結果值。它們分別對應邏輯運算中的與運算AND 和或運算OR。它們的運算結果取決於兩個操作數(operand)的關係:

第一個操作數
a
第二個操作數
b
結果 
a && b
結果
a || b
true true true true
true false false true
false true false true
false false false false

例如 :

( (5 == 5) && (3 > 6) ) 返回false ( true && false ).
( (5 == 5) || (3 > 6)) 返回true ( true || false ).

條件運算符Conditional operator ( ? )

條件運算符計算一個表達式的值並根據表達式的計算結果爲真true或假false而返回不同值。它的格式是:

condition ? result1 : result2 (條件?返回值1:返回值2)

如果條件condition 爲真true,整個表達式將返回esult1,否則將返回result2。

7==5 ? 4 : 3 返回3,因爲7不等於5.
7==5+2 ? 4 : 3 返回4,因爲7等於5+2.
5>3 ? a : b 返回a,因爲5大於3.
a>b ? a : b 返回較大值,a 或b.

// 條件運算符例子

#include <iostream>
using namespace std;

int main ()
{
  int a,b,c;

  a=2;
  b=7;
  c = (a>b) ? a : b;

  cout << c;

  return 0;
}
7                  

上面的例子中a的值爲2,b的值爲7,所以表達式(a>b)運算值爲假(false),所以整個表達式(a>b)?a:b要取分號後面的值,也就是b的值7。因此最後輸出 c 的值爲7。


逗號運算符 ( , )

逗號運算符 (,) 用來分開多個表達式,並只取最右邊的表達式的值返回。

例如有以下代碼:

a = (b=3, b+2);

這行代碼首先將3賦值給變量b,然後將 b+2 賦值給變量 a。所以最後變量a 的值爲5,而變量b的值爲3

位運算符Bitwise Operators ( &, |, ^, ~, <<, >> )

位運算符以比特位改寫變量存儲的數值,也就是改寫變量值的二進制表示:

op asm Description
& AND 邏輯與 Logic AND
| OR 邏輯或Logic OR
^ XOR 邏輯異或Logical exclusive OR
~ NOT 對1取補(位反轉)Complement to one (bit inversion)
<< SHL 左移Shift Left
>> SHR 右移Shift Right

變量類型轉換運算符Explicit type casting operators

變量類型轉換運算符可以將一種類型的數據轉換爲另一種類型的數據。在寫C++中有幾種方法可以實現這種操作,最常用的一種,也是與C兼容的一種,是在原轉換的表達式前面加用括號()括起的新數據類型:

int i; 
float f = 3.14;
i = (int) f;

以上代碼將浮點型數字3.14轉換成一個整數值(3)。這裏類型轉換操作符爲(int)。在C++中實現這一操作的另一種方法是使用構造函數constructor 的形式:在要轉換的表達式前加變量類型並將表達式括在括號中:

i = int ( f );

以上兩種類型轉換的方法在C++中都是合法的。另外ANSI-C++針對面向對象編程(object oriented programming)增加了新的類型轉換操作符 (參考Section 5.4, Advanced class type-casting).


sizeof()

這個運算符接受一個輸入參數,該參數可以是一個變量類型或一個變量自己,返回該變量類型(variable type) 或對象(object)所佔的字節數:

a = sizeof (char);

這將會返回1給a,因爲char是一個常爲1個字節的變量類型。

sizeof返回的值是一個常數,因此它總是在程序執行前就被固定了。


其它運算符

在本教程後面的章節裏我們將看到更多的運算符,比如指向指針的運算或面向對象編程特有的運算,等等,我們會在它們各自的章節裏進行詳細討論。


運算符的優先度 Precedence of operators

當多個操作數組成複雜的表達式時,我們可能會疑惑哪個運算先被計算,哪個後被計算。例如以下表達式:

a = 5 + 7 % 2

我們可以懷疑它實際上表示:

a = 5 + (7 % 2) 結果爲6,還是 a = (5 + 7) % 2 結果爲0?

正確答案爲第一個,結果爲6。每一個運算符有一個固定的優先級,不僅對數學運算符(我們可能在學習數學的時候已經很瞭解它們的優先順序了),所有在C++中出現的運算符都有優先級。從最從最高級到最低級,運算的優先級按下表排列:

優先級
Level
操作符
Operator
說明
Description
結合方向
Grouping
1 :: 範圍 從左到右
2 () [] . -> ++ -- dynamic_cast static_cast reinterpret_cast const_cast typeid 後綴 從左到右
3 ++ -- ~ ! sizeof new delete 一元(前綴) 從右到左
* & 指針和取地址
+ - 一元符號
4 (type) 類型轉換  從右到左
5 .* ->* 指向成員的指針 從左到右
6 * / % 乘、除、取模 從左到右
7 + - 加減 從左到右
8 << >> 位移 從左到右
9 < > <= >= 關係操作符 從左到右
10 == != 等於、不等於 從左到右
11 & 按位與運算 從左到右
12 ^ 按位異或運算 從左到右
13 | 按位或運算 從左到右
14 && 邏輯與運算 從左到右
15 || 邏輯或運算 從左到右
16 ?: 條件運算 從右到左
17 = *= /= %= += -= >>= <<= &= ^= |= 賦值運算 從右到左
18 , 逗號 從左到右


結合方向Grouping定義了當有同優先級的多個運算符在一起時,哪一個必須被首先運算,最右邊的還是最左邊的。

所有這些運算符的優先級順序可以通過使用括號parenthesis signs (和)來控制,而且更易讀懂,例如以下例子:

a = 5 + 7 % 2;

根據我們想要實現的計算的不同,可以寫成:

a = 5 + (7 % 2); 或者 
a = (5 + 7) % 2;

所以如果你想寫一個複雜的表達式而不敢肯定各個運算的執行順序,那麼就加上括號。這樣還可以使代碼更易讀懂。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章