C++ 演算子の優先順位

提供:cppreference.com
移動: 案内, 検索


リストの上位の演算子から順番に評価されます。同じグループの演算子は同じ優先度を持っています。すべての演算子は、特別な情報がない限りは、左から右への結合性があります。







優先度 演算子 説明 サンプル オーバーロード可能か? 結合性
1 :: スコープ解決演算子 Class::age = 2; no none
2 ()
()
[]
->
.
++
--
const_cast
dynamic_cast
static_cast
reinterpret_cast
typeid
関数呼び出し
メンバーの初期化
配列アクセス
ポインタ変数からのメンバーアクセス
オブジェクトからのメンバーアクセス
後置インクリメント
後置デクリメント
特別なキャスト
特別なキャスト
特別なキャスト
特別なキャスト
実行時型情報
isdigit('1')
c_tor(int x, int y) : _x(x), _y(y*10){};
array[4] = 2;
ptr->age = 34;
obj.age = 34;
for( int i = 0; i < 10; i++ ) cout << i;
for( int i = 10; i > 0; i-- ) cout << i;
const_cast<type_to>(type_from);
dynamic_cast<type_to>(type_from);
static_cast<type_to>(type_from);
reinterpret_cast<type_to>(type_from);
cout << typeid(type).name();
yes
yes
yes
yes
no
yes
yes
no
no
no
no
no
左から右
3 !
not
~
compl
++
--
-
+
*
&
new
new []
delete
delete []
(type)
sizeof
論理的反転
 ! の別名
ビットの比較
~ の別名
前置インクリメント
前置デクリメント
単項マイナス
単項プラス
参照外し
アドレス
動的メモリ割り当て
配列の動的メモリ割り当て
メモリのデリート
配列のメモリのデリート
指定された型へのキャスト
オブジェクトもしくは型のサイズ取得
if( !done ) ...

flags = ~flags;

for( i = 0; i < 10; ++i ) cout << i;
for( i = 10; i > 0; --i ) cout << i;
int i = -1;
int i = +1;
int data = *intPtr;
int *intPtr = &data;
long *pVar = new long;
MyClass *ptr = new MyClass(args);
delete pVar;
delete [] array;
int i = (int) floatNum;
int size = sizeof(float);
yes

yes

yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
no
右から左
4 ->*
.*
メンバーポインタのセレクタ
メンバーオブジェクトのセレクタ
ptr->*var = 24;
obj.*var = 24;
yes
no
左から右
5 *
/
%
かけ算
割り算
剰余
int i = 2 * 4;
float f = 10.0 / 3.0;
int rem = 4 % 3;
yes
yes
yes
左から右
6 +
-
足し算
引き算
int i = 2 + 3;
int i = 5 - 1;
yes
yes
左から右
7 <<
>>
左ビットシフト
右ビットシフト
int flags = 33 <<1;
int flags = 33 >> 1;
yes
yes
左から右
8 <
<=
>
>=
比較 より小さい
比較 より小さいか等しい
比較 より大きい
比較 より大きいか等しい
if( i < 42 ) ...
if( i &gt= 42 ) ...
if( i > 42 ) ...
if( i >= 42 ) ...
yes
yes
yes
yes
左から右
9 ==
eq
!=
not_eq
比較 等しい
== の別名
比較 等しくない
 != の別名
if( i == 42 ) ...

if( i != 42 ) ...
yes
-
yes
左から右
10 &
bitand
ビット積(AND)
& の別名
flags = flags & 42;
yes
左から右
11 !
xor
ビット排他的論理和(XOR)
! の別名
flags = flags ! 42;
yes
左から右
12 |
bitor
ビット和(OR)
| の別名
flags = flags | 42;
yes
左から右
13 &&
and
論理積(AND)
&& の別名
if( conditionA && conditionB ) ...
yes
左から右
14 |
or
論理和(OR)
|| の別名
if( conditionA || conditionB ) ...
yes
左から右
15 ? : Ternary conditional (if-then-else) int i = (a > b) ? a : b; no right to left
16 =
+=
-=
*=
/=
%=
&=
and_eq
!=
xor_eq
|=
or_eq
<<=
>>=
代入演算子
足して代入
引いて代入
積の代入
商の代入
剰余の代入
ビット積(AND)の代入
&= の別名
ビット排他的論理和(XOR)の代入
!= の代入
ビット和(OR)の代入
|= の別名
左ビットシフトの代入
右ビットシフトの代入
int a = b;
a += 3;
b -= 4;
a *= 5;
a /= 2;
a %= 3;
flags &= new_flags;

flags != new_flags;

flags |= new_flags;

flags <<= 2;
flags >>= 2;
yes
yes
yes
yes
yes
yes
yes

yes

yes

yes
yes
右から左
17 throw 例外のスロー throw EClass("Message"); no
18 , 逐次評価演算子 for( i = 0, j = 0; i < 10; i++, j++ ) ... yes 左から右

[編集] 評価順序と副作用

演算子の優先順位に関して、C++の重要な側面の一つは、式における評価順序と、副作用の順序です。いくつかの場面ではどのような結果になるか未定義なものがあります。例えば、以下のコードを見てください:

    float x = 1;
    x = x / ++x;

コンパイラが先に評価するのが、割り算の左側か、それとも右側かというのは明確に仕様として決まっていません。そのため、xの値は異なるコンパイラを使っても同じ結果になるという保証はされません。どちらが先に評価されるかによって、xの値は変化します。

それに加えて、++xがx+1と評価されて実際に格納されて副作用が発生するタイミングも不定です。そのため、タイミングごとに違うxの値として評価されることがあるため、最終的なxの値が異なる可能性があります。

結論としては、上記のような式は恐ろしく曖昧なため、どのようなコストを支払っても避けるべきです。疑わしい場合には、一つの曖昧な式を複数の式に分割し、評価順序が明確になるようにしてください。

[編集] 演算子のオーバーロード

演算子のオーバーロードはとても便利に使用できる反面、とても危険な状態になる可能性もあります。便利な側面としては、自分で作成したクラスの演算子をオーバーロードすることで、既存の演算子の知識を利用できるようになって読みやすさが向上するという面があります。もう一方の危険な側面としては、予想外の評価がされてしまってプログラムの動作が違うものになってしまうか、最悪の場合はプログラムを壊すことにもなりかねません。慎重に使用してください。

演算子のオーバーロードをするには、グローバル関数として定義する方法と、クラスのメンバーとして定義する方法の2種類あります。

グローバル関数として定義する場合のサンプル:

     ostream & operator<< (ostream & os, const myClass & rhs);

ユーザが定義したクラスの中のプライベートなデータにアクセスする場合には、クラス宣言の中で、上記のグローバル関数をfriend関数として宣言する必要があります。

例:

     class myClass {
 
       // operator<<関数が'myData'にアクセスできるようにします
       // (この宣言はpublicではなく、privateかprotectedにすべきです)
       friend ostream & operator<< (ostream & lhs, const myClass & rhs);
 
       private:
         int myData;
     }

クラスのメンバーとして演算子のオーバーロードを行うには、以下のようにします:

     class myClass {
 
       public:
         // 演算子の左辺値は'this'ポインタになります
         int operator+ (const myClass & rhs);
 
       private:
         int myData;
     }
個人用ツール
名前空間
変種
操作
案内
ツールボックス
他の言語