MSB8012警告
http://www.orangemaker.sakura.ne.jp/labo/memo/VS2008/msb8012warning.html
ポインタ:
変数のアドレスを格納するための変数
型 *p で宣言、&を付けて変数のアドレス、*pでpに格納されているアドレスが指す値
オーバーライド
クラス継承時、派生クラスにおいて基本クラスのメンバ関数と同じシグネチャの関数を定義すると
オーバーライドすることができる。
メンバ関数がある場合class, そうでない場合structがよい
クラスのメンバはディフォルト非公開、構造体のメンバはディフォルト公開
関数をインライン化
inlineをつけるか、関数の定義をクラスの宣言に含める
制限:ループ×、再帰×、gotoとswitch ×、static ×
(どんな関数でもインライン化できる)
メンバ関数の定義が短い:クラス定義の中に含めた場合自動インライン化される
(inlineを付ける必要なし、付けてもよい)
インラインコンストラクタ
オブジェクトの代入:
代入は同じ型のオブジェクトのみ
メンバ関数にポインタを使用しているとエラーの原因となる可能性
動的メモリ注意
関数へオブジェクトを引き渡す:
渡すクラスの型で関数の仮引数を宣言
フレンド関数(家族ではないが親しい友人みたいな感じ):
クラスの非公開メンバにアクセスできる
クラス宣言で”friend”を付けてプロトタイプ宣言
(複数クラスにフレンド登録OK、継承×)
使用法:クラスのオブジェクトを引き渡して使うことが多い
用途例:型の異なるクラスにおける共通要素の比較
プロトタイプ宣言, 前方宣言:
引数がないと前方宣言
関数のオーバーロード:
引数の型もしくは数、またはその両方が異なる必要あり
戻り値の型が異なるだけ×
派生クラス:
基本クラスの公開メンバ関数呼び出し可
(基本クラスの公開要素はすべて引き継がれる)
クラスと構造体:
クラスのメンバ:デフォルト非公開
構造体のメンバ:デフォルト公開
関数からオブジェクトを返す:
1) 返すクラスの型で関数宣言
2) return文でその型のオブジェクトを返す
※返す際に戻り値を格納する一時オブジェクトが作られる。
実際にはこれが返される。返した後、一時オブジェクトは破棄される。
オブジェクトのポインタ:
オブジェクトポインタをインクリメント、次のオブジェクトを指す
オブジェクトの配列などで便利
thisポインタ:
メンバ関数を呼び出したときに自動的に渡される
例) ob.samp(); //samp関数にobを指すポインタが自動的に渡される
このポインタはthis参照できる
※フレンド関数では使えない
numb = 123.456; //これは下の文の省略形
this->numb = 123.456;
関数を呼び出したオブジェクトを指す
new/delete
(メモリを割り当てるオブジェクトを指すポインタ) = new (オブジェクトの型);
delete (メモリを割り当てるオブジェクトを指すポインタ);
配列の動的確保など
malloc/free と比べて:
型キャスト必要なし、サイズは自動的に判別される、<cstdlib>必要なし
deleteによるメモリの解放は、1要素と配列で異なる
delete p1;
delete [] p2;
ポインタ:
&は変数のアドレスを取り出す
配列の場合は&a[0]で取得
ポインタを使うときは初期化を忘れないようにする
参照(ポインタに似ている):
用途) 関数への仮引数として(参照仮引数)
ほかの変数または引数として機能する
※参照は引数でないとき、宣言部分で初期化されなければならない
参照仮引数:
利点:呼び出しに使用したオブジェクトのコピーは作成されない
参照を使用する際の手続きが簡略化される
欠点:呼び出しに使用した変数に影響を及ぼす可能性
void f(int &n); //参照仮引数を宣言
int main()
{
int i = 0;
f(i);
return 0;
}
void f(int &n)
{
n = 100; //iに100が代入される、nは関数を呼び出すのに使われた引数へのポインタ
}
参照が指すものを変更することできない(ポインタとの違い)
参照仮引数を使用しての関数呼び出し時、引数に&演算子を付けない
オブジェクトの参照渡し:
参照仮引数を使用して関数にオブジェクトを渡すと、オブジェクトのコピーは作成されないので、
デストラクタによるエラーを避けられる
参照を使用してオブジェクトのメンバにアクセスするときはドット演算子を使う
参照返し:
関数から参照を返す
int &f(); //参照を返す
int x;
int main()
{
f() = 100; //f()が返す参照に100を代入する
cout << x << “\n”;
return 0;
}
int &f() //int型の参照を返す
{
return x; //xへの参照を返すのでxに100が代入される
}
※参照を返す場合、参照先のオブジェクトがスコープから外れないように注意
コンストラクタのオーバーロード:
オブジェクトの初期化方法を選択できる
クラスの動的配列を割り当てる
コピーコンストラクタ:
関数にオブジェクトを渡したり、関数からオブジェクトを返したりする際に、
元のオブジェクトのコピーが作られる。これが原因でエラーを引き起こす可能性。
コピーコンストラクタを定義しておけば、コピーが作成された際にコピー用のメモリが割り当てられる。
コピーコンストラクタはオブジェクトの初期化時に呼び出される(宣言、引数、戻り値)
※コピーコンストラクタは代入操作では作動しない。初期化のみ
クラス名(const クラス名 &obj) { コンストラクタ本体 }
obj = ほかのオブジェクトを初期化するために使われるオブジェクトの参照
デフォルト引数:
関数の呼び出し時に対応する引数がしてないときに使われる。
例)void f(int a=0, int B=0);
上記の場合、3通りの呼び出し方がある(a, b 2つの引数を指定、aのみ, 引数を指定しない)
※aはデフォルト、bは指定のパターンは駄目
1つ目のデフォルト引数を指定したら、それ以降の仮引数にもデフォルト値を与えなければいけない
つまりデフォルト値を持たない仮引数は持つものよりも左に書く必要がある
ほかの仮引数、ローカル変数はデフォルト引数として使えない
関数オーバーロードの代わりとして使える状況もある
コンストラクタにデフォルト引数を使用することによって、
コンストラクタのオーバーロードをしないで済む場合も多い。
オーバーロードのあいまいさ:
型変換、参照仮引数、デフォルト引数、関数そのもの、呼び出し方法などを因とする
オーバーロード関数に不適切な型を渡すと、自動変換規則によりあいまいさが生じる
参照仮引数orデフォルト値の値呼び出し仮引数の選択しかないオーバーロード関数を作るとあいまいさが生じる
オーバーロード関数でデフォルト引数を使うとあいまいさが生じることがある
オーバーロード関数のアドレス:
ポインタの宣言方法により、どの関数のアドレスを取得するか決まる
ポインタの宣言が不適切だとあいまいさが生じる
演算子オーバーロード:
関数オーバーロードの一種
演算子の持つ本来の意味が失われるわけではない、新しい意味が付与される
たいていはクラスでメンバ(フレンド)関数として定義される(operator-symbolでオーバーロードする演算子を指定)
本来の動作を逸脱しない範囲で用いるのがよい
2項演算子のオーバーロード:左のオペランドは暗黙的に関数に渡され、右のオペランドは引数として渡される
単項演算子のオーバーロード(オペランド1つ)
派生クラスは、=を除くすべての演算子関数を継承する
参照仮引数の使用でパフォーマンス向上
フレンド演算子関数:
フレンド関数はthisポインタを持たない
二項演算子では、二つのオペランドが明示的に渡される
代入演算子のオーバーロードはメンバ演算子関数のみ
フレンド演算子関数を使用することにより、組み込み型を演算子の左で使うことができる(ob = 10 + ob;)
オーバーロードする演算子をフレンドにしておけば、オブジェクトの位置に神経を尖らせる必要が無くなる
friend coord operator+ (coord ob1, int i);
friend coord operator+ (int i, coord ob1);
添え字演算子:
[]演算子のオーバーロードを使用して、通常の配列と変わりなく使用できる、安全な配列をつくることができる
※配列の境界チェックにはオーバーヘッドが伴う
代入演算子のオーバーロード:
ディフォルトのビット単位コピーでは都合が悪いときに使う。
コピーコンストラクタ、代入演算子の呼ばれるタイミング:
samp x; //デフォルトコンストラクタ
samp y = x; //xによるyの初期化、コピーコンストラクタ
samp z; //デフォルトコンストラクタ
z = x; //代入演算子
基本クラスのアクセス制御:
アクセス指定子で基本クラスの要素の継承方法を決定する(public, private, protected)
基本クラスをpublicとして継承しても、派生クラスが基本クラスの非公開メンバにアクセスできるわけではない
privateで継承すると、基本クラスの公開メンバは派生クラスの非公開メンバになる
その場合でも派生クラスの内部ではそのメンバにアクセスできる
protected(被保護)アクセス指定子:
private指定子とほとんど一緒
派生クラスのメンバ関数からはアクセスできる
それら以外からはアクセスできない
コンストラクタ、デストラクタ、継承:
コンストラクタは派生順、デストラクタは逆順
多重継承(2パターンある):
1)基本クラスから派生クラスを作り、その派生クラスを基本クラスとして派生クラスをつくる。
その場合、最初の基本クラスを間接基本クラスと呼ぶ。
2)派生クラスが複数の基本クラスを継承
仮想基本クラス:
派生クラスが複数の基本クラスを直接継承することによって生じるあいまいさを回避するための機構
通常の基本クラスとの違いは継承のされかたのみ
入出力マニピュレータ:
入出力文の内部で使用する
マニピュレータが引数を取らないときは括弧が付かない
cout << oct << 100; //octフラグ
iosメンバ関数と比べて使い勝手がよい
boolalphaをオンにしておけば、true/falseを直接使用できる
ファイル入出力:
<fstream>をインクルードする
ifstream in; //入力
ofstream out; //出力
fstream io; //入出力
あらゆるファイルは、バイナリモードとテキストモードのどちらでも開くことができる。
ifstream mystream(“myfile”); //一般的なファイルの開き方
mystream.close(); //ファイルの閉じ方
bool eof(); //関連づけられたファイルの最後に達した場合trueを返す
派生クラスへのポインタ:
基本クラスへのポインタとして宣言されたポインタは、
その基本クラスから派生したどのクラスを指し示すのにも使用できる。
アクセスできるのは派生クラスのメンバのうち、基本クラスから継承されたもののみ。
仮想関数:
基本クラス内で宣言され、派生クラス内で再定義されるメンバ関数
仮想関数を含むクラスが継承されると、継承したクラスはその仮想関数を自分自身に関して再定義する
仮想関数の再定義では、仮引数の型と個数、戻り型が同一でないといけない。
仮想関数はクラスのメンバでなければならない
デストラクタは仮関数でありえるが、コンストラクタはなりえない
オーバーライドとも呼ばれる
基本クラスポインタを通じて仮想関数にアクセスするとき、
オーバーライドされた仮想関数のどのバージョンが実行されるかは、
指し示されたオブジェクトの型で決まる
純粋仮想感想:
仮想関数を純粋仮想関数の形で宣言した場合、派生クラスは必ずその関数をオーバーライドしなければならない
少なくとも1個の純粋仮想関数を含むクラスを抽象クラスと呼ぶ
抽象クラスは不完全な型であり、そのクラスのオブジェクトは作成できない
コンパイル時バインディング:
コンパイル時にわかっているイベントのこと
利点:効率の良さ 欠点:柔軟性を各
実行時バインディング:
実行時にならないとわからないイベントのこと
利点:柔軟性 欠点;呼び出しのためのオーバーヘッドが大きい
インライン関数:
関数自体が使用される箇所に埋め込まれる
呼び出しよりも処理が早いが使いすぎるとプログラムが肥大化する
短い関数は呼び出すよりもインライン化したほうが効率がよい
クラスのメンバ関数を含めどんな関数でもインライン化できる
クラス内でのstatic:
変数の場合、静的メンバ変数となり、そのクラスのインスタンス間で共有される
関数の場合、静的メンバ関数となり、インスタンスを作らずにアクセスできるようになる
静的メンバ関数からアクセスできるのは静的メンバ変数のみ
名前空間:
C++のライブラリ全体は、stdという専用の名前空間で定義されている
無名名前空間:
namespaceキーワードに”名前空間の名前”を指定しない
名前の有効範囲をファイルスコープに制限する
staticクラスメンバ:
メンバ変数をstaticとして宣言→そのクラスのオブジェクトを複数作成しても、その変数のコピーはひとつ
複数のオブジェクトが単一の変数を共有する
staticメンバは、宣言されたクラス内にスコープが限定されているグローバル変数
メンバ関数をstaticとして宣言するのは一般的でない
多次元配列:
array[i][j] は要素j個の配列を1要素とする、要素i個の配列。
一番目の配列のサイズは省略できる
ポインタ:
レジスタ変数には&演算子は使えない(メモリ上にアドレスを持たないから)
配列とポインタ:
配列は先頭要素へのポインタという形で受け渡しを行う。
ポインタとして受け取った引数は、
1)*演算子を使用してアクセス
2)[]演算子を使用して配列のように扱う
関数から参照を返す:
int &f() { return x; }
この関数はxのアドレスを返す。
代入文の左辺で関数を使うことができる。
配列:
配列の名前はポインタであり、値をしてその先頭アドレスを持つ
例)int z[10]
zは配列zの先頭アドレス、i個後ろの要素は*(z+i)、またはz[i]と書ける
ポインタの配列:
*ptr は ptr[0] と書くことができる
*ptr[0] は ptr[0][0] と書くことができる
またi番目の要素は *(ptr[0] + i) または ptr[0][i]
配列の名前は、その配列の先頭要素のアドレス
type a[] は type *a と解釈される
関数へのポインタ宣言は、関数名の前に*をつけて()で囲む
静的なメンバ変数:
非静的なメンバ変数 : オブジェクトに属する
静的なメンバ変数 : クラスに属する
静的なメンバ変数は、そのクラスのオブジェクトが複数作られても、一つしか存在しない。
つまり、オブジェクト間で共有される。
静的なメンバ関数:
実体が無くても呼び出すことができる
静的なメンバ関数が扱うことができるのは静的なメンバのみ
staticの様々な意味:
関数本文の外側の変数 : この変数のスコープはそれが宣言されているファイル内
関数の内側の変数 : 永続的、コピーは一つしか作られない
関数宣言 : この関数のスコープはそれが宣言されているファイル内
メンバ変数 : クラス毎に一つのコピーしか作られない
メンバ関数 : クラスの静的なメンバにのみアクセス可
定数ポインタ:
const char *test_ptr1 = “This is a test.”
この場合、test_ptr1がポイントしているデータが定数となる(上記の場合、char配列)
従って、test_ptr1 = “Hello” は正しく、
*test_ptr1 = ‘X’1 は正しくない
ポインタを定数にするには、constをアスタリスクの後に置く
char *const test_ptr2 = “Test”
この場合は、test_ptr2は定数ポインタ
従って、test_ptr2 = “Something” は正しくなく、
*test_ptr2 = “N” は正しい
キャスト:
static_cast : 静的なキャスト、intからdouble, doubleからfloatなど、一般的なキャストに使われる
const_cast : constやvolatileを除去するために使われる
reinterpret_cast : 強制的にビット構成を変更する(通常、使用する機会はない)
dynamic_cast : キャスト可能かを判定するために使われる
丸め誤差:
浮動少数点数は正確ではなく、計算の回数が多くなるほど丸め誤差が大きくなる
金額の計算は整数で行うほうがよい
浮動小数点数は本質的に正確ではない
float と double の計算速度:
すべての演算をdoubleで行うコンパイラもあるので、
float型で宣言された変数のほうが速いとは限らない。
配列の受け取り:
1) void func (int a[10])
2) void func (int a[])
3) void func (int *a)
引数として配列を受け取る場合、上記のような記述の仕方がある。
これらはすべて同じ意味であり、コンパイラは 3) として解釈する。