☆文法
_◇リンク時の名前
C++では
⇒ソースコードの関数名の後に引数や戻り値の型情報を付加した名前をリンカにわたす。
⇒(関数オーバロードなどがあるため)
⇒名前はマングリングが行われる(人間可読な名前ではなくなる)
⇒よってCでコンパイルした関数をC++で呼び出そうとするとみつからずにリンクエラーとなる
※extern “C” { … }
この中で宣言される関数についてはC++の名前の変形を行わない宣言
_◇Cの関数を通過するC++の例外
C++では
⇒例外は深い階層の関数から投げられることがある
⇒例外は呼び出し階層の複数の関数を通過してより上位の関数でキャッチされることがある
⇒例外が認識された後、途中のスタックが巻き戻され、必要なデストラクタが呼び出される必要がある
⇒C++の例外オブジェクトは、Cの関数を通過できない
⇒Cの関数が途中にハマっているとスタックの巻き戻しも正常にできない
⇒例外がC/C++の境界を通過しないように配慮するのが穏当。代替手段を工夫するのは自己責任じゃ。
◆コメント
その行の残りはコンパイラによって無視される。
//
_◇単文、複文
単文
│ simple statement
複文
│ compound statement
文のグループ化(複文)
{}による
◆変数、定数宣言
※C++のオブジェクト
値を表現するための記憶域
_◇定数記述
1U 符号なし整数の1
~0U 符号なし整数0の反転なのでオールビット1
⇒<climits>のUNIT_MAXと同じ
_◇列挙体
enumeration
enum 列挙体名 { 列挙子, … }
※列挙子
enumerator
_◇typedef宣言
構文)
typedef 型名 識別子;
例)
typedef unsigned long int Count;
⇒unsigned long int型にCountという独自の名前をつけた
_◇変数型
※組み込み型
built-in type
char -128..127
unsigned char 0..255
⇒ビット数は<climits>ヘッダで、マクロCHAR_BITで定義される
⇒処理系依存。少なくとも8
short int -32768..32767
unsigned short int 0..65535
int -2147483648..2147483647
unsigned int 0..4294967295
※以下も4バイトなので同じ
long int
unsigned long int
float 3.4e-38..3.4e38
double 1.7e-308..1.7e308
※以下も8バイトなので同じ
long double
※論理型 bool
1バイト true または false を保持
⇒true と false は論理リテラル
⇒trueとfalseを整数型に変換する場合
true->1
false->0
⇒整数型をbool型に変換する場合
0以外の整数→true
0->false
※標準C++で許可されている符号付き数の表現法は3種類ある
①2の補数表現 2’s complement representation
②1の補数表現 1’s complement representation
③符号付き絶対値表現 signed magnitude representation
※wchar_t
Unicodeなどで表現されたワイド文字を保持するための型
⇒内部はintやlongなどの整数型のどれかと同じ
⇒Cでは、typedefで定義される型だった
⇒C++では組み込み型となったが、Cの名残で_tがついている
_◇変数宣言
declaration
構文)
型名 識別子;
variable_type variable_name;
※同じ型の変数を2つ以上宣言する場合、カンマを使って区切る
※変数名には、文字と数字と「_」が使える
※キーワードは変数名には使えない
※宣言時の値の代入
変数型 変数名 = 値;
⇒変数の初期化と代入は異なるものとして区別される
※Cと異なり、変数を使う前であればどこででも変数宣言を行うことができる
⇒forやifなどのブロック先頭で宣言することで、宣言したブロック内だけで通用する変数とできる。
※クラス型の宣言記法
int(i) int iに同じ
int() … クラスのデフォルトコンストラクタと同様にかけるようにしたもの。初期値は0
int(100) … リテラル100をint型キャスト
_◇文字列
NTBS
null-terminated byte string
NULL文字で終わるchar型の配列(C言語形式の文字列)
例)
char fnam[64];
※文字列の終わりはNULL文字(ASCIIコードの0, ‘\0′)
※文字列定数はダブルクォートで囲む
⇒文字列定数を生成するとコンパイラが自動的にNULL文字を代入する。
※シングルクォートで囲んだ場合は、NULL文字を含む文字列ではなく、文字定数となる
※配列宣言時に初期化できる。
例)
char title[]=”TITLE”;
※配列同様に文字列を引数として関数に渡すことができる。(配列の大きさを指定する必要はない)
※文字列は配列としてもポインタとしても扱うことができる。
※文字列リテラル(例 “ABC”)の型は、const char* である。
_◇ワイド文字型
wchar_t型
│ cではtypedefだが、C++では予約語
│ ワイド文字定数は L’c’
char16_t, char32_t型 C11/C++11で規格化
UTF-16とUTF-32が
_◇ユーザー定義型
user defined type
クラスもユーザ定義型に含まれる
①列挙型
enumerated data type
構文)
enum 列挙型名 {識別子1, 識別子2, 識別子3, …};
列挙型名 列挙変数名;
例)
enum Week {SUN, MON, TUE, WED, THU, FRI, SAT};
Week w;
⇒列挙型Weekの変数wの宣言;
②構造体型
structure data type
構造体型宣言 構文)
struct 構造体型名 { 型名 識別子; 型名 識別子; ... }
例)
struct Car { int num; double gas; };
構造体変数の宣言 構文)
構造体型名 構造体変数名;
例)
Car car1;
※構造体メンバへのアクセス
構文)
構造体変数名.メンバ
例)
car1.num = 1234;
※構造体の初期化
構文)
構造体型名 構造体変数名 = {値, 値, …};
※構造体どうしでの代入
⇒メンバをひとつずつコピーして値を格納する
※構造体を引数としてとる関数
⇒実引数の構造体のメンバの値がコピーされて関数本体に渡される
⇒大きな構造体の場合オーバヘッドが大きい
※構造体へのポインタを引数としてとる関数
⇒構造体へのポインタを使って各メンバにアクセスする処理
アロー演算子
構文)
構造体へのポインタ->構造体メンバ
※構造体変数への参照を引数としてとる関数
⇒ドット演算子でメンバにアクセスできる
例)
void show(Car& c) { c.num ... }
③共用体型
union data type
共用体型の宣言 構文)
union 共用体型 { 型名 識別子; 型名 識別子; ... }
⇒共用体型は各メンバのどれか一つの値しか記憶できない。
_◇型変換
基本ルール)
演算子に異なる型のオペランドを記述した場合、一方のオペランドを大きなサイズの方に型変換してから演算を行う
※暗黙の型変換
異なる型の変数に代入しようとすると、型の変換が行われる。記憶域の小さい型に大きい型から代入する場合は要注意⇒切り捨てが起こる
_◇静的な型と動的な型
※静的な型 static type
実行時の意味を考慮せずに、プログラムの形だけからきまり、実行中に変わらない。
プログラム解析により得ることができる。
※動的な型 dynamic type
左辺値式の表す左辺値が指す最派生オブジェクトの型
⇒クラスBへのポインタが、クラスBから派生したクラスのオブジェクトを指していたとすると、動的な型は派生クラス。参照も同じ。
_◇不完全型
※識別子のサイズを決定するために必要な情報が描けている型。
①メンバがまだ指定されていない構造体型
②メンバがまだ指定されていない共用体型
③次元がまだ指定されていない配列型
⇒以上の不完全な型は同じスコープ内で宣言すれば完全な型となる。
④voidは完全にすることができない不完全型
_◇大域変数
プログラムの最初で、どの関数に対しても内部にならないような場所で大域変数を宣言できる
※大域変数名と局所変数名が衝突する場合、大域解決演算子によって大域変数を参照できる。(単純に参照すると局所変数となる)
例)
│ ::number
※グローバル変数を初期化しない場合、0で初期化される。
_◇局所変数とスコープ
関数の定義の最初で中括弧の後に続けて変数宣言することで、その変数は局所変数となる
※異なる関数の中の局所変数の名前が同じでも、変数の衝突は起こらない
※ローカル変数
local variable
関数の中で定義。変数宣言の場所から関数の末尾までの間利用できる。
※グローバル変数
global variable
関数の外で定義。どの関数からでも利用できる。
※グローバル変数とローカル変数の名前が重複した場合
①ローカル変数のスコープ内ではローカル変数によりグローバル変数は隠ぺいされる。
②グローバル解決演算子「::」によりグローバル変数にもアクセスできる
例)
│ ::a++;
※ローカル変数を初期化しない場合の初期値は不定
※staticでないローカル変数へのポインタや参照を戻り値としてはならない。
_◇記憶クラス指定子
storage class identifier
ローカル変数に static キーワードを指定することで、グローバル変数同様な静的寿命をもつローカル変数とできる。
※static 変数を初期化しない場合は0で初期化される
※静的データメンバ
①静的データメンバの実体はクラス定義の外でstaticを付けずに
クラス名::データメンバ名
という形式で定義する。ただし、
②静的データメンバが constつき汎整数型か列挙型に限り、初期化子をクラス定義の中で与えても良い。
_◇const修飾子
※定数
constant
構文)
const 型名 識別子 = 式;
⇒const指定をした変数は、初期化時以外、値を設定することができない定数となる。
※const引数
⇒関数の引数にconstを指定すると、その関数の中では書き換えられなくなる。
⇒constをつけない参照渡しは関数により中身を書き換えられる可能性があるが、constによって中身を書き換えないと宣言できる。
※constポインタ
⇒ポインタ宣言にconstをつけることで、ポインタの指す内容を書き換えることができなくなる。
※constメンバ関数
⇒メンバ関数の宣言の末尾にconst修飾子をつけることで、そのメンバ関数を呼び出してもオブジェクトが変化しないことを宣言できる
⇒constオブジェクトに対してもconstメンバ関数は呼び出せる。
例)
int get_height() const;
_◇参照
reference
プログラム中の変数に対して別名を生成する
関数の中での引数の変更を簡単にすることができる。
※参照の宣言
型の後に「&」を続けて指定する
型名& 参照名 = 変数;
⇒参照は必ず参照の対象となる変数で初期化する。
例)
int& alias_name = variable;
※宣言後は通常の変数と同様に使うことができる。しかし、参照は変数でないので、一度割り当てた変数は変更できない。また、ポインタと異なりアドレス演算子を適用したり、値を比較したり、オフセットを加えたりする演算はできない。
※参照引数
関数(型& alias)
{
│ aliasへの代入
※呼び出す側で、関数の引数として参照を渡す。
⇒これにより「*」を使わずに引数を変更して結果を戻すことができる。
※参照を仮引数とした関数
⇒実引数として変数を渡すと、参照である仮引数は実引数で初期化される
⇒参照渡しが実現できる
※ポインタに代入はできない。
※参照にはコメントをつけること
※仮引数に const 指定をつけると、ポインタでも、参照でも、関数内で値を変更することはできなくなる。
※参照を返すことでゲッタ兼セッタをつくる
例)
Type& first() { return v1; }
⇒インスタンス.first()でv1を読みだすことができる
⇒インスタンス.first()=xxxでv1にxxxを代入することができる
_◇配列
配列の型 配列の名前[配列の大きさ];
例)
int test_array[100];
※配列要素の最初はインデックス[0]なので、最後の配列要素のインデックス値は配列の大きさより1少ない
※宣言時に配列を初期化できる。
⇒初期化子 (initializer)
例)
int values[5] = { 10, 20, 30, 40, 50 };
⇒初期化する配列の大きさが指定されなければ、指定された要素数を保持できるように割り当てる。
※関数に配列を渡すことができる。配列の型は必要だが、配列の大きさを指定する必要はない。しかし、通常は配列の要素数を別に与えて処理させる
例)
void func(int array[], int number_of_elements);
{
│ …
func(array_name, 5);
※配列名はポインタ変数と似たような操作ができるが、配列名であらわされるポインタには、ほかのアドレスを代入することができない
※動的な配列の確保
⇒プログラムの実行時に配列の大きさを決める場合には、配列を動的に確保する。
ポインタ名 = new 型名[要素数];
delete[] ポインタ名;
_◇ポインタ
pointer
ポインタはアドレスを格納する変数
ポインタ宣言構文)
型名* ポインタ名;
例)
int* pA;
※voidへのポインタ
添字演算子[]や間接演算子*による領域のアクセスは行えない。
⇒reinterpret_cast<const char*>に変換すればバイトアクセスできる。
⇒変換したポインタを char* 型変数 x に代入すれば配列 xでハイトアクセスできる
⇒&x[i*size]などとすれば、sizeバイトのオブジェクトの先頭ポインタとなる
⇒これをreinterpret_cast<const void*>で戻せば、void*として関数に渡せる
⇒汎用関数を作成する場合に便利
※ポインタは反復子としても利用できる
_◇構造体
structure
異なった型のメンバから構成される関連情報をまとめた変数
まず構造体を定義し、それから構造体の変数を宣言する
例)
struct name { int member1; float member2; } variable;
※name(構造体名)は構造体タグとも呼ばれ、これを使って構造体変数を宣言することもできる
name a, b, c;
キーワート struct を構造体名の前においてもよい(通常のCと互換。C++では省略可)
struct name a, b, c;
※構造体メンバへのアクセスはドット演算子を使う
例)
st.member1
※関数が構造体を更新しない場合には、構造体の名前を関数に渡して参照することができる
※構造体の定義は、呼び出される関数、呼び出す関数の前にあること
※関数が引数を更新する場合、アドレス演算子でアドレスを渡し、メンバへはポインタでアクセスしなければならない。
例)
pointer_variable->member1
※構造体メンバについてもアクセス指定子を指定することができる。
クラスメンバと異なり、省略した場合はpublicとなる
_◇共用体
union
共用体は、最大のメンバを保持できるメモリが割り当てられる。メンバで同じメモリをシェアする
例)
union distance { int miles; long meters; };
distance japan, germany, france;
※ドット演算子を使って共用体メンバを参照できる
※無名共用体
anonymous union
名前を持たない共用体
例)
union { int miles; long meters; };
⇒共用体型の変数宣言せず、通常の変数宣言位置に配置する。ドット演算子を使わずに通常の変数のようにアクセスできる。ただし、メモリはシェアされる
_◇メモリ自由領域
free store
動的なメモリの確保(dynamic allocation)のために使われる。
※動的記憶領域=ヒープ領域
※演算子 new
実行時にメモリを割り当てるために使用する
⇒クラス型に対してnewを適用すると、コンストラクタが呼び出される。(コンストラクタによって初期化が行われる)
⇒非クラス型に対してnewを適用した場合
│ pt = new T; *ptに格納される値は不定
│ pt = new T(); ゼロで初期化
⇒newは実行時にエラーが生じた場合、std::bad_alloc例外を投げる
例)
int* pA;
pA = new int;
⇒まず確保する型へのポインタを容易する。
⇒new演算子で、メモリを確保し、確保したメモリのアドレスを得て、それをポインタへ格納する。
例)
char *buffer = new char[50];
⇒ポインタ変数に50バイトのメモリへのポインタを代入
※自由領域に空きメモリが無く必要なメモリが割り当てられない場合 NULL値が返される
※演算子 delete
演算子 deleteに開放すべきメモリへのポインタを指定することでメモリが開放される
例)
delete pointer;
※割り当てられたメモリを開放せずにプログラムが終了すると、通常は自動的に開放される。しかし、deleteを使って開放すれば、再利用することができる
※メモリが割り当てられなかった場合に呼び出される固有のハンドラの定義
set_new_handler(呼び出したい関数名);
※newやdeleteの再定義
⇒演算子のオーバーロード機構による
例)
static void operator delete(void *pointer)
{
│ …
※C++の場合、newしたものが単独オブジェクトか、配列かでdelete演算子も変わる。
⇒間違えた時の動作は未定義。
p = new T;
…
delete p;
p = new T[n];
…
delete[] p;
_◇代入演算子
assignment
構文)
変数名 = 値;
※代入式を評価すると左辺に代入された型と値が得られる。
_◇算術論理演算子
+ 加算
– 減算
* 乗算
/ 除算
% 剰余(あまりを求める)
~ 1の歩数、値のビット反転 complement operator
& ビットAND bitwise AND operator
| ビットOR bitwize inclusive OR operator
^ ビットXOR bitwize exclusive OR operator
<< ビット左シフト x << y xの全ビットをyビットだけ左シフト
>> ビット右シフト x >> y yの全ビットをyビットだけ右シフト
│ ⇒左右合わせて bitwize shift operator
│ ⇒オペランドは汎整数型か列挙型
│ ⇒coutへの挿入子<< cinの抽出子>>は、シフト演算子の多重定義
※負の数のシフト演算は処理系依存
⇒プログラムの可搬性が損なわれるので非推奨。
※インクリメント、デクリメント演算子
++
—
※接頭演算子と、接尾演算子がある
インクリメントしてから参照するか
参照してからインクリメントするか
※単項演算子
unary operator
オペランドが一つのオペレータ
_◇関係演算子
relational operator
== 等しいか
!= 等しくないか
> 最初の値が2番目の値より大きいか
< 最初の値が2番目の値より小さいか
>= 最初の値が2番目の値より大きいか等しい
<= 最初の値が2番目の値より小さいか等しい
※比較の結果は、真か偽のどちらか
│ 真: 非0
│ 偽: 0
_◇論理演算子
&& 論理AND
|| 論理OR
! NOT演算子h
_◇sizeof演算子
sizeof operator
型や式のサイズを調べる
⇒文字を表すのに必要な大きさの何倍かを返す
⇒通常バイト数と一致する
⇒sizeof(char)は必ず1
例)
sizeof(short)
_◇キャスト演算子
cast operator
※明示的型変換演算子
書式)「古いキャスト」「キャスト記法」Cの方式
(型名) 式
例)
│ (int)3.14
書式)関数的記法 (Cでは使えずC++でのみ使える)
型(x)
例)
│ int(3.14)
※新しいキャスト
書式 キャスト演算子<キャスト後の型名>(キャスト対象)
キャスト演算子
①static_cast
static_cast<型>(x)
⇒xを指定された型に変換した値を生成
⇒列挙と整数型間
⇒任意の型へのポインタとvoid型ポインタ間
コンパイル時にチェックされ、実行時には返還後の型は決定済
例)static_cast<int>(aaa)
暗黙変換がある場合。使用可。
②const_cast
const_cast<型>(x)
constやvolatile属性を除去するためのキャスト、コンパイル時にチェック
⇒constで宣言された変数にそうでない変数を代入するなど。
例)
const int c=25;
int n = const_cast<int>(c);
⇒const int型の値をint型としてとりだす。
③reinterpret_cast
reinterpret_cast<型>(x)
強制的にビット構成を変更する。通常使用しない。Win32APIの一部で使用
double* からlong longなどへの無理やりキャスト
⇒ポインタから整数へ、あるいは、整数からポインタといった型変換で利用
④dynamic_cast(動的キャスト)
dynamic_cast<型>(x)
⇒アップキャストで使う
⇒ダウンキャストが許される場合においてそれを行う場合に使われる。
キャスト可能か否かを実行時に判断する。不可能ならヌルを返す
⇒Cにはない
⇒参照型のキャスト失敗時には例外bad_castが投げられる。
⇒ポインタ型のキャスト失敗時にはNULLポインタが返る。
※dynamic_cast演算子の変換対象は仮想関数を持つ多相的クラスであること
⇒ポインタ型へのキャストに失敗した場合、変換先の型を持つ空ポインタ値
⇒参照型へのキャストに失敗した場合、bad_castが投げられる
⇒動的キャストを行った場合、変換後のポインタが空ポインタでないか、あるいは例外が投げられていないかどうかの確認が必須
※ダウンキャスト
基本型のポインタを派生型のポインタに変換する(危ない)
⇒dynamic_castは避けるべき(仮想関数を使って記述する)
⇒ポインタ/参照の指す先のオブジェクトが、変換先のオブジェクトへのポインタ/参照型と等しい時に限り、動的キャストによって基底クラスへのポインタ/参照を派生クラスへのポインタ/参照に変換するダウンキャストが可能となる。
※アップキャスト(具象クラスのポインタを抽象クラスに代入)
⇒明示的なキャストは不要(上位のクラスでは下のクラスでできることはできる)
_◇条件演算子
conditonal operator
書式)
条件 ? 真の時の値 : 偽の時の値
_◇アドレス演算子と間接参照演算子
※アドレス演算子
&
アドレス演算子により、変数のアドレスを取得することができる
例)
&a
⇒aのアドレスを得る
※間接参照演算子
indirection operator
*
変数名の前に「*」をつけることでポインタ変数を宣言することができる。
ポインタ変数にはアドレスを格納する。
ポインタ変数のアドレスの指す先を参照する場合、ポインタ変数の前に「*」をつけることで参照する
例)
*pA
※よい習慣
ポインタ変数の宣言時に変数のアドレスで必ず初期化する。
⇒うっかりポインタが何もさしていない状態になるのを防ぐ。
_◇ポインタ演算
※文字列
char *string
文字配列の最初の要素へのポインタが渡される
│ (*string != ‘\0’)
で文字列の末尾のNULL文字か否かが判断できる
非0値は真なので
│ while(*string) { …
と書いて判断できる
ポインタのインクリメントまで兼ねれば
│ while(*string++) { …
※文字列以外の配列型にポインタを使用する場合、配列の要素数を引数により指定しなければならない
例)
&test[0] 配列の先頭要素のアドレスを示す
&test[1] 配列の2番目の要素のアドレスを示す
test 配列の先頭要素のアドレスを示す
⇒配列名は、配列の先頭要素のアドレスを格納しているポインタと同じ働きを持つ
※実在しない「末尾要素のひとつ後方の要素」へのポインタをもとめる演算は有効
例)
│ int a[5];
│ for (int *p = &a[0]; p != &a[5]; p++) …
※ポインタ演算
p+1 pがさしている要素の次の要素のアドレス
p-1 pがさしている要素の前の要素のアドレス
p1-p2 p1とp2の間の要素数
p++ pがさしている要素の次の要素のアドレスを得る
p– pがさしている要素の前の要素のアドレスを得る
※ポインタに[]演算子を使う
subscript operator
⇒ポインタが配列をさしているときには、ポインタに[]をつけて、さし示す要素をあらわすことができる。
※クラスのデータメンバへのポインタの宣言
型名 クラス名::*ポインタ名
⇒アクセスは、間接.*演算子による
インスタンス変数.*ポインタ名
※静的データメンバの場合は、
型名 *ポインタ名
として宣言してもよい。(静的メンバは各オブジェクトとは無関係に一つだけ存在するため)ポインタの代入は、&クラス名::変数名とする。
例)
int *ptr = &StaticMember::x;
_◇演算の優先順位
①
:: スコープ解決 クラス名::クラスメンバ名
:: 大域解決 ::変数名
②
. メンバ選択 オブジェクト.メンバ名
-> メンバ選択 ポインタ->メンバ名
[] 添え字 ポインタ[要素]
() 関数呼び出し 関数(引数)
() 型変換値生成 型(引数)
sizeof オブジェクトサイズ sizeof式
sizeof 型のサイズ sizeof(型)
③
++ 接尾インクリメント
++ 接頭インクリメント
— 接尾デクリメント
— 接頭デクリメント
& アドレス演算子
* 間接参照演算子
new メモリ割り当て演算子
delete メモリ開放演算子
delete[] 配列の開放
~ 1の補数 ~式
! 否定
+ 単項プラス
– 単項マイナス
() キャスト (型)式
④
.* メンバ選択 オブジェクト.*ポインタ
->* メンバ選択 オブジェクト->*ポインタ
⑤
* 乗算
/ 除算
% 剰余
+ 加算
– 減算
※括弧でくくることで、順序を制御できる
※左結合
left associative
⇒四則演算の演算子は、優先順位が同じ場合、左から順に計算する
※右結合
right associative
⇒単項演算子と代入演算子は、優先順位が同じ場合、右から評価される
_◇多重定義できる演算子
new
delete
+ 単項、2項
– 単項、2項
* 単項、2項
/
%
^
& 単項、2項
|
~
!
= 非メンバ関数としては定義不可
<
>
+=
-=
*=
/=
%=
^=
&=
|=
<<
>>
>>=
<<=
==
!=
<=
>=
&&
||
++
—
,
-> 非メンバ関数としては定義不可
->*
() 非メンバ関数としては定義不可
[] 非メンバ関数としては定義不可
※多重定義できない演算子
.
.*
::
? :
_◇キャスト演算子のオーバーロード
※型変換キャスト演算子をクラス定義の中でオーバーロードすることができる。
⇒グローバル関数として定義することはできない
例)
class sample { public: operator int() { return 1; } ...
※使用時
│ int iv = (int)sample;
でも
│ int iv = int(sample);
でも
│ int iv = sample;
でもよい。
_◇typeid演算子
※実行時型情報 RTTI
run-time type information
実行時に型が決定する文脈におけるRTTIを取得する演算子
RTTI=run-time type identification 実行時型識別 のこともある
書式)
typeid x
│ 式xの型識別のための情報を生成する。
│ ⇒int, doubleなどの基本型にたいしても適用できる
│ ⇒オペランドが式である場合
│ 静的な型 const type_info
│ 動的な型 const type_infoの左辺値または const name
│ const nameはtype_infoから派生した処理系定義のクラス
│ ⇒type_infoオブジェクトへの参照が返る
│ ⇒ポインタが空ポインタの場合は bad_typeid例外
※type_infoクラス
<typeinfo>ヘッダで提供される
処理系が生成する型情報を現すためのクラス
①型名を表す文字列へのポインタ
②型の同等性や順序を比較するための符号化された値
⇒具体的な表現法は処理系依
⇒ == !=は定義される。
※bad_typeidクラス
<typeinfo>ヘッダで提供される
typeid式に空ポインタが含まれた場合に例外として投げられるオブジェクト型
exceptionクラスの派生クラス
_◇通常の算術変換
usual arithmetic conversion
2つの異なる型のオペランドに対する演算時には、同じ型に変換した上で演算が適用される。
⇒算術型または列挙型
⇒変換された型が結果の型でもある
※以下上から適用
①どちらか一方が long double型ならlong double型に統一
②どちらか一方が double型ならdouble型に統一
③どちらか一方が float型ならfloat型に統一
④演算対象の両方を汎整数昇格
⇒bool型、wchar_t型、列挙型も汎整数型の一つに変換される
⑤どちらか一方が unsigned long型ならunsigned long型に統一
⑥一方がlong intで他方がunsigned int、かつ long intがunsigned intの全ての値を表現できるならばlong int型に統一。表現できないときは、unsigned long int型に統一。
⑦どちらか一方がlong int型ならlong int型に統一
⑧こちらか一方がunsigned int型なら unsigned int型に統一
※上記規則の結果 int型とunsigned int型の混在演算では unsigned int型に統一される
⇒int型の -1は unsigned int型でオールビット1に変換される
_◇符号付き整数と符号無し整数間の型変換規則
※2の補数表現の場合の原則
①符号付き整数型から、同一ビット数の符号無整数型への変換ではビットパターンは変化しない。
②符号付き整数型から、よりビット数の多い符号無整数型への変換では符号拡張
③符号付き整数型から、よりビット数の少ない符号無整数型への変換では上位切り捨て
① signed X ⇒ signed Y
ビット数 値
X≦Y x
X>Y xがsigned Yで表現可能なら x, 不能の場合は処理系依存
② unsigned X ⇒ signed Y
X<Y x
X≧Y xがsigned Yで表現可能なら x, 不能の場合は処理系依存
③ signed X ⇒ unsigned Y
X < Y x≧0 x
│ x<0 (signed Y)x + (1+Y_MAX)
X = Y x≧0 x
│ x<0 x + (1+Y_MAX)
X > Y x≧0 x % (1+Y_MAX)
│ x<0 (1+Y_MAX)-(-x % (1+Y_MAX))
④ unsigned X ⇒ unsigned Y
X≦Y x
X>Y x%(1+Y_MAX)
_◇汎整数昇格
integral promotion
①char, signed char, unsigned char, short int, unsigned short int型の右辺値
⇒その型の全てがint型で表現できる場合には、int型の右辺値に変換できる
⇒そうでない場合は、unsigned int型の右辺値に変換できる。
②wchar_tまたは列挙型の右辺値
⇒以下の型のうち、型の全ての値を表現できる型の中でもっとも左の型の右辺値に
int, unsigned int, long, unsigned long
③汎整数のビットフィールドの右辺値が、ビットフィールドの全てをint型で表現できるならば、int型に変換
そうでない場合にunsigned int型で表現できるならば、unsigned int型
ビットフィールドがさらに大きければ汎整数昇格はしない
ビットフィールドが列挙型をもつ場合、昇格のためには列挙型のとらない別の値として扱われる。
④bool型の右辺値はint型の右辺値となる。falseが0、trueが1
_◇浮動小数点昇格
floating point promotion
①float型の右辺値は、double型の右辺値に変換できる
_◇汎整数変換
integral conversion
①整数型の右辺値は、別の整数型の右辺値に変換できる。
列挙型の右辺値は、整数型の右辺値に変換できる。
②目的の型が符号無し型の場合、結果の値は、元の整数の値に合同な最小の符号無整数(2^nを法とした剰余)
⇒丸めがなければビットパターンに変更はない
③目的の型が符号有り型の場合、その値が表現できる場合には値は変化しない。そうでない場合は処理系定義
④目的の型がbool型の場合は、真理値変換による。元の型がbool型ならfalseは0、trueは1に変換
⑤汎整数昇格の変換は、汎整数変換とは言わない
_◇浮動小数点変換
floating point conversion
①浮動小数点型の右辺値は、別の浮動小数点型に変換できる
元の型での値が目的型でも正確な値にできる場合はそうなる
目的の型では2つの値の中間になる場合は、どちらかになるかは処理系定義
そうでない場合は未定義
②浮動小数点昇格に許される変換は、浮動小数点変換とは言わない
_◇浮動小数点数と汎整数の間の変換
floating-integral conversion
①浮動小数点型右辺値は、整数型の右辺値に変換できる。
⇒小数点部分を切り捨てる
⇒切り捨てた値が目的の型で表現できない場合は、未定義
②整数型または列挙型の右辺値は浮動小数点型の右辺値に変換できる
⇒目的の型で表せる場合は正確な値
⇒目的の型では2つの値の中間となるばあいは、どちらになるかは処理系定義
(精度は劣化する)
⇒元の型がboolの場合、falseは0、trueは1
_◇真理値変換
boolean conversion
算術型、列挙型、ポインタ型およびメンバへのポインタ型の右辺値はbool型の右辺値に変換できる。ゼロ、空ポインタ、空メンバポインタ値はfalse、その他はすべてtrue
_◇ブロック
block
{ } にかこまれた部分
_◇if文
if (条件) 文; if (条件) 文; else 文; if (条件) 文; else if (条件) 文; else if (条件) 文; else 文;
_◇for文
for (初期化; テスト; 増加)
│ 文;
※ループ中では省略表記を使うことが多い。
c += 5
c = c + 5
_◇while文
while (条件)
│ 文;
_◇do ~ while ループ
do { 文; } while (条件);
_◇switch
構文)
switch () { case 値1: 文1; ~ break; case 値2: 文2; ~ break; ~ケース~ default: 文; ~ break; }
_◇反復子
イテレータ
データ構造に含まれる各要素に対する繰り返し操作を抽象化する仕組み
⇒データ構造の種類を問わず、同じ方法で要素を操作できるようにする
※イテレータを2つ使うことにより、範囲を示すこともできる。
ポインタを抽象化した概念
⇒反復子に * 演算子を適用することで要素にアクセスできる
要素を操作する反復子 vector<型>::iterator型
先頭要素を指す反復子はbegin()メソッドで、末尾+1はend()メソッドで得られる
⇒非const版とconst版の両方が多重定義されている
⇒要素数0ならbegin()とend()は同一値を返す
#include <vector> #include <iostream> using namespace std; int main() { vector<int> v(5); int value = 0; for (vector<int>::iterator p = v.begin(); p != v.end(); p++) *p = ++value; for (vector<int>::const_iterator p = v.begin(); p != v.end(); p++) cout << *p << ' '; cout << '\n'; }
※反復子の種類
①入力反復子 InputIterator
++による要素移動と *による参照が可能
②出力反復子 OutputIterator
++による要素移動と *による代入が可能
③前進反復子
++による要素移動と *による参照と代入が可能
(入力反復子+出力反復子の機能)
④双方向反復子(BidirectionalIterator 両進反復子)
++ — による要素移動と *による参照と代入が可能
⑤ランダムアクセス反復子 RandomAccessIterator
++ — による要素移動と *による参照と代入が可能
difference_type型整数の加減算による要素移動+ – += -=
反復子同士の減算-
反復子同士の比較<
任意位置要素をアクセスする[]
⇒ポインタはランダムアクセス反復子としての条件を満たす。
※逆進反復子
vector<型>::reverse_iterator
末尾型から先頭側へと走査する
⇒走査そのものは++演算子による
rbegin()で末尾要素への反復子が得られ、rend()で先頭要素のひとつ先が返る。
※end(), rend()の返す反復子は存在しない要素を指すので、それに++や*を適用してはならない。
※diffrence_type型
同一コンテナ内の要素を示す反復子どうしを減算すると、それらの指す要素が何要素分はなれているかが得られる。
⇒ポインタに類似
⇒反復子に対してはdiffrence_type型整数の加減算が可能
⇒ベクトルの中央を示す反復子
v.begin() + v.size() / 2
※ポインタは反復子としても利用できるので、走査の対象を反復子で受け取る関数テンプレートは、ベクトルだけでなく配列や各種のコンテナ型も扱える
※反復子を受け取る関数テンプレート例
#include <vector> #include <iostream> using namespace std; template<class InputIterator> void print(InputIterator first, InputIterator last) { cout << "{"; for (InputIterator i = first; i != last; i++) cout << *i << " "; cout << "}"; } int main() { int a[] = {1, 2, 3, 4, 5}; vector<int> x(a, a + 5); cout << "a = "; print(a, a+5); cout << '\n'; cout << "x = "; print(x.begin(), x.end()); cout << '\n'; }
_◇コンテナと反復子の種類
※ランダムアクセス反復子
vector<>, deque<>, string<>
※双方向反復子
list<>, set<>, multiset<>, map<>, multimap<>
_◇iterator_traits<>クラステンプレート
反復子の特性を表す
※受け取った反復子の特性を取り出すときなどに使う
template <class Iterator> struct iterator_traits { typedef typename Iterator::difference_type difference_type; typedef typename Iterator::value_type value_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; typedef typename Iterator::iterator_category iterator_category; };
_◇関数宣言
function definition
戻り型 関数名(仮引数リスト) { 変数宣言; 文; }
※値を戻す場合 return文で値を戻す
例)
return 0;
※仮引数
parameter
⇒関数の本体で定義されている引数
※実引数
argument
⇒関数の呼び出し元から渡される引数
※引数リスト
「,」で引数を区切る
※引数のない関数の定義
無指定または void とする
_◇インライン関数
inline function
構文)
inline 戻り値の型 関数名(仮引数リスト) { ~ }
_◇関数の呼び出し
関数名(実引数リスト)
※関数の引数名の並びに対して引数の値を左から右に代入する
※C++の場合、関数に渡されるのは変数に格納されている値である
⇒pass by value
⇒構造体やオブジェクトをそのまま渡すと、クラスなどのメンバをコピーして新しいオブジェクトが作られる。(⇒コピーコンストラクタ)
⇒元の構造体やオブジェクトそのものを操作したいときは参照で渡す。
※参照渡し(pass by reference)
実質的に参照するためには、ポインタを関数に渡す
※配列引数
プロトタイプ宣言例)
double avg(int t[]);
⇒要素数の指定のない配列を仮引数とする
呼び出し例)
avg(test);
⇒配列名を実引数として渡す。
_◇引数のデフォルト値
関数を呼び出す場合に引数を省略できる
省略した引数にはデフォルト値が使われる
※デフォルト値の指定
代入演算子により、関数定義の引数に値を代入する
例)
void some_function(int size=12, float cost=19.95)
{
│ …
⇒デフォルト引数は右から順に設定しなければならない。(ある引数のデフォルト値を設定した場合は、その引数以降の全引数にデフォルト引数を指定しなければならない。)
※デフォルトの値が与えられる関数の引数を省略して呼び出す場合、省略された引数に続くすべての引数を省略しなければならない
_◇関数プロトタイプ
function declaration
関数が呼び出される前に、関数が戻す値の型と、引数の型をコンパイラに知らせる宣言
例)
int add_val(int, int);
※関数プロトタイプ宣言内で、デフォルト引数を指定することもできる
構文)
戻り値の型名 関数名(型名 仮引数名=デフォルト値, ~);
_◇main関数
プログラムの実行開始位置を示す。
例)
void main(void)
_◇void
関数が値を戻さない、関数に渡す値がない
_◇関数のオーバーロード
function overloading
C++では C と異なり同じ名前と戻り値を持つ関数を複数定義することができる。C++コンパイラは、コンパイル時にそれぞれの関数が使う引数を調べて正しい関数を呼び出す
※オーバーロードについて特に指定する必要はない
⇒引数の型や数が異なっていれば、同じ名前を持つ関数を複数定義できる。
※引数の数や型が異なる、似たような処理を同一の関数名で定義して使う。
⇒処理の実態がそれぞれ異なって良い
⇒戻り値も異なった型で良い
⇒ただし、引数の型や数は違う必要がある。
※多態性(Polymorphism)のひとつ
⇒一つの名前が、状況に応じて別々の働きをもつ
_◇関数テンプレート
function template
※関数テンプレートは処理内容は同一で型が異なる場合に使う
※関数テンプレートの利用手順
①関数テンプレートを宣言、定義する。
②関数を呼び出す(と、関数が自動的に生成される)
※関数テンプレートの宣言・定義
template <class テンプレート引数のリスト>
⇒これを通常の関数宣言に先だって指定する
⇒テンプレート引数は「仮の型名」を指定したもの
⇒関数宣言では、仮引数の型名や、戻り値の型名に「仮の型名」であるテンプレート引数を使って記述する。
例)
template<class T> T max(T a, T b) { if ( a > b ) return (a); else return (b); }
⇒文字 T はテンプレートの総称的な型
⇒次にプロトタイプ宣言により実際の関数が生成される
⇒具現化(instantiation)
⇒プロトタイプ宣言をしないで呼び出す場合、テンプレートに与えるべき型が実引数の型から明らかになる場合は省略可能
例)
float max(float, float);
int max(int, int);
※複数の型を使ったテンプレート
例)
template<class T, class T1> void show_array(T *array, T1 count)
{
│ …
void show_array(int *, int);
void show_array(float *, unsigned);
_◇関数テンプレートの利用要件
関数の内部でのTの使い方によるが
①コピー構築可能
CopyConstructible
│ テンプレートを具体化する際の型Tに対して
│ tが型Tの値
│ uが型const Tの値であるとき、
│ tがT(t)と等価
│ uがT(u)と等価
│ tに対してデストラクタを呼び出すことが可能
│ &t, &uによってtとuへのポインタが得られる
②代入可能
Assignable
│ テンプレートを具体化する際の型Tに対して
│ tが型Tの値
│ uが型const Tの値であるとき、
│ 代入式 t = uによって、tがuと等価になり
│ かつ代入式がTへのポインタを生成する
※int, doubleなどの基本型は、コピー構築可能かつ代入可能
_◇テンプレートの部分特殊化
partial template specialization
テンプレートにおいて、特定のテンプレート実引数が与えられたときに、元と異なる定義を使用させるようにする仕組み
※明示的特殊化
explicit specialization
明示的な特殊化を行うクラステンプレート定義の形式
⇒クラステンプレートCを型Tに特殊化する場合
template <> class C<T> { ... };
_◇関数ポインタ
※関数を指すポインタ
⇒関数ポインタの「型」は指す対象となる関数の型に依存する
⇒Type func(…)型の関数fを指すポインタfpの宣言
Type (*fp)(…) = f;
※「int型の引数を受け取ってdouble型の値を返却する関数」へのポインタ
double (*fp)(int);
⇒変数名fpを()で囲まないとdouble型へのポインタを返す関数の宣言となってしまうので注意
※関数名は、その関数へのポインタと解釈される
⇒関数fへのポインタは, &fとしても良いし、fでもよい
⇒関数ポインタにより、呼び出す関数を実行時に決定する動的呼び出しを実現できる
※関数ポインタ:仮引数の宣言に限り、変数名の前の*と、それらを囲む()を省略した形式で宣言できる。
※関数呼び出し式 f(…)
⇒左オペランド f は関数名そのものでなく、関数ポインタでもよい
⇒よって、(*fit)(…) を fit(…)と書いてもよい。
※構文の変遷
①標準C以前
関数呼び出し式の構文:
│ 1次式(実引数並び)
⇒f()は関数を表す一次式であるfに対して関数呼び出し演算子()を適用した式
⇒関数へのポインタfpは一次式でないのでfp()とはできなかった
⇒間接演算子を適用して*fpとして一次式にしてから演算子()を適用する必要があった
⇒(*fp)()
②標準C
│ 後置式(実引数並び)
⇒関数へのポインタ型へと型変換された後置式であるfに対して関数呼び出し演算子()を適用
⇒関数へのポインタfpも後置式とみなされるのでfp()と書ける
⇒(*fp)()でも動作するが間接演算子*は冗長
⇒f(), *f(), **f(), fp(), *fp(), **fp()は皆同じ
⇒関数名に対してアドレス演算子&を適用するとその関数へのポインタが生成される
(ポインタへのポインタにはならない)
⇒fは関数fへのポインタだが、&fも関数fへのポインタ
※空ポインタ(整数値0)の代入
⇒関数へのポインタには空ポインタを代入してもよい
※異なる関数型へのポインタ代入は通常不可
※引数を受け取らず値を返却しない関数へのポインタを要素型とする配列の宣言例
void (*afp[])() = {dog, cat, monkey};
⇒afp[0]()などとすれば呼び出すことができる
※関数へのポインタにtypedef名を与えることで通常の配列のように宣言することができる
例)
typedef void (*AnimalFP)();
AnimalFP afp[] = {dog, cat, monkey};
※関数へのポインタを返却する関数
void dog() { ... void (*slected_animal())() { ... return dog; int main() { void (*animal)() = selected_animal() if (animal == NULL) break; animal(); ...
※メンバ関数(非静的)へのポインタ
メンバ関数へのポインタを使う場合には、通常の関数ポインタではコンパイルエラーとなる。
⇒所定の引数を受け取り、所定の値を返却する指定クラスに所属するメンバ関数へのポインタとして宣言しなければならない
書式)
返却値型 (クラス名::*関数ポインタ変数名)(仮引数並び)
例)
int (SimpleDate::*ptr)(int) const = &SimpleDate::comp_y;
int diff = ptr(2017);
※間接ドット演算子と間接アロー演算子
indirection .* operator
indirection ->* operator
x.*y
オブジェクトxのメンバyが指すオブジェクトまたは関数を表す。
x->*y
xが指すオブジェクトのメンバyが指すオブジェクトまたは関数を表す
◆関数オブジェクト(ファンクタ)
function object
functor
※関数をオブジェクトとしてメモリ空間に確保したもの
⇒関数ポインタでコールバックを記述すると、コールバックした先では
コールバック元のローカル変数を参照できない
※オブジェクトのクラスにおいて operator()メンバ関数を定義すると、
関数呼び出し演算子の多重定義により、そのオブジェクトのインスタンスを指す
変数の変数名が、あたかも関数名であるかのような構文で定義した関数を呼ぶことができる。⇒コールバックされたときには、関数ポインタではなくオブジェクトが渡されるので、オブジェクトの他のメンバに対してアクセスできる
※関数呼び出しと同じ構文で、メンバ関数を呼ぶことができるオブジェクト
※標準関数オブジェクト
│ ()演算子を多重定義している
_◇unary_functionとbinary_function
ファンクタを定義するときに継承すべきstruct
※unary_functionの定義例
template <class Arg, Class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; };
※binary_functionの定義例
template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; };
_◇ファンクタの利用
※for_eachによる利用
#include <algorithm>
for_each(x.begin(), x.end(), ファンクタ());
※クラステンプレートとして定義されたファンクタは
クラス名<型名>()でオブジェクトを生成し、それの()演算子を呼び出すので
以下のようにすれば、直接呼び出すことができる
例)
less<int>()(15, 37)
※transformによる利用
コンテナ内の連続する要素に対して一括処理を行う
①入力コンテナ要素⇒単項ファンクタ⇒格納先コンテナ
│ 入力コンテナ要素first, last, 格納先result, ファンクタop
②入力コンテナ要素1と2⇒2項ファンクタ⇒格納先コンテナ
│ 入力コンテナ要素first1, last1, first2,
│ 格納先result, ファンクタop
_◇リンケージ
※外部リンケージ
⇒名前がすべてのファイルで適用すること(適切なヘッダのインクルードは必要)
※内部リンケージ
⇒名前がファイル内に限定される
⇒ローカル変数は内部リンケージ
※グローバル変数、関数
⇒外部リンケージを持つ
⇒static をつけて内部リンケージとすることができる
※extern
別ファイルのグローバル変数の参照用の宣言
例)
extern int a;