C++ のお勉強 クラス編
C++ のお勉強二日目。前回の「C++ のお勉強 関数編」の続きになる。
だんだん C++ が解ってきた…気がする。
クラスとかオブジェクトとかみんなカッコイイこと言ってるから,クラスは難しいもんだと思っていたけど,ただの構造体じゃないか。C だってうまくすれば構造体の中に関数もてるよ。まぁ隠蔽は出来ないんだけどさ。
参照変数
- C のポインタのようなもの
- 書式が普通の変数と見分けが付かない
- 参照変数宣言時に代入する必要がある
- クラスをパラメーターとして渡すときに便利
#include <stdio.h> int main() { int x = 10; int &y = x; //これが参照変数 y++; printf("x %d y %d \n", x, y); // => x 11 y 11 return 0; }
クラス
- C の構造体を拡張したものにすぎない
- メンバーとして変数の他に関数も持つことができる
- さらに,それぞれのメンバーにアクセス制限をかけることが出来る
- 次のようなアクセス修飾子を記述した部分以降のすべてのメンバーに適用される。また,省略時は private が適用される
種類 | クラス内からのアクセス | 継承クラスからのアクセス | 外部関数からのアクセス |
---|---|---|---|
private | ○ | × | × |
protected | ○ | ○ | × |
public | ○ | ○ | ○ |
-
- あるクラス型として宣言された変数はオブジェクトと呼ばれる
- 次のコードで a はClass1型のオブジェクトである
- あるクラス型として宣言された変数はオブジェクトと呼ばれる
#include <stdio.h> class Class1 { public: int id; void show() { printf("%d, %s\n", id, name); } } int main() { Class1 a; a.id = 10; a.show(); // => 10 return 0; }
-
- メンバ関数はプロトタイプ宣言可能で,上下のコードは等価
#include <stdio.h> class Class1 { public: int id; void show(); } void Class1::show() { printf("%d, %s\n", id, name); } int main() { Class1 a; a.id = 10; a.show(); // => 10 return 0; }
演算子のオーバーロード
つまり,
c = a + b;
この計算は,
c = a.(operator+)(b);
と解釈される。
- 例えば次のようにベクトルの足し算が可能
#include <stdio.h> class Vector { int x, y; public: void set(int tmp_x, int tmp_y) { x = tmp_x; y = tmp_y; }; void show() { printf("x %d y %d \n", x, y); } Vector operator+ (Vector &v) { Vector c; c.x = x + v.x; c.y = y + v.y; return c; } }; int main() { Vector a, b, c; a.set(1, 2); b.set(2, 3); a.show(); // => x 1 y 2 b.show(); // => x 2 y 3 c = a + b; c.show(); // => x 3 y 5 return 0; }
メモリの動的確保
int *pi = new int;
delete pi;
代入と初期化
#include <stdio.h> class Color { public: int r, g, b; Color() { r = g = b = 0; } ~Color() { printf("object is deleted\n"); } }; int main() { Color *pc = new Color; print("r %d g %d b %d \n", pc->r, pc->g, pc->b); // => r 0 g 0 b 0 delete pc; // => object is deleted }
継承
- クラスは別クラスに引き継ぐことができる
- このとき,基になったクラスを基底クラス。派生したクラスを派生クラスと呼ぶ
- また,基底クラスが複数の場合を多重継承と呼ぶ
- 派生クラスの宣言方法:
class クラス名 : [アクセス権] 基底クラス名 [,[アクセス権] 基底クラス名…] {
変更部分
};
-
- アクセス権の指定で,基底クラスから派生クラスへのメンバの取り込み方を制御できる
- private なら基底クラスのすべてがプライベート部に入れられる
- public なら基底クラスのパブリックメンバーはそのまま派生クラスのパブリック部に入れられる
- 何も指定しなければ,基底クラスが struct ならば public,class ならば private と等価
- 派生クラスの初期化は,まず基底クラスのコンストラクタが呼ばれ,続いて派生クラスのコンストラクタが呼ばれる
- したがって,派生クラスのコンストラクタには,基底クラスの初期設定に必要なパラメータを記述する
- メンバの先頭に virtual を付ければ,派生クラスでそのメンバを再定義できる。この関数は仮想関数と呼ばれる
- アクセス権の指定で,基底クラスから派生クラスへのメンバの取り込み方を制御できる
#include <stdio.h> class Pencil { protected: int core; // 鉛筆の芯の長さ public: Pencil(int n) { core = n; } void write() { if (--core < 0) // 書くたびに芯が 1mm ずつ小さくなる core = 0; } virtual void info() { // これが仮想関数 printf("core %d \n", core); } }; class ErasePencil : public Pencil { protected: int rubber; // 消しゴムの大きさ public: ErasePencil(int a, int b) : Pencil(a){ // 基底クラスのコンストラクタにパラメーターを渡す rubber = b; } void remove() { if (--rubber < 0) // 消すたびにゴムが 1 立方mm ずつ小さくなる rubber = 0; } virtual void info() { // この仮想関数に再定義される printf("core %d rubber %d \n", core, rubber); } }; int main() { Pencil pen1(15); pen1.write(); pen1.info(); // => core 14 ErasePencil pen2(20, 10); pen2.write(); pen2.remove(); pen2.info(); // => core 19 rubber 9 return 0; }