補足説明
サンプルプログラムの構成 str.h str.cpp main.cpp 文字列処理用のモジュール 分割コンパイルができなくなるので、ヘッダファイルには実装は書かない str.h クラスの宣言 を記述 #include “str.h” main.cpp メインルーチン #include “str.h” str.cpp クラスに含まれる メンバ関数の 本体を記述 Stringクラスのメンバ関数にスコープ String:: を書くのを忘れない char& String::getChar(int i) { }
ヘッダファイルの中身 #ifndef __MYSTR__ #define __MYSTR__ class String { char *s; 二重インクルードの防止措置 もし、 __MYSTR__ が定義されていなかったら、以下を定義しますよ。すでに定義されていたら、定義が重複しないように読み飛ばしますよ。 __MYSTR__の部分はプログラムを書く人が決めた文字列 #ifndef __MYSTR__ #define __MYSTR__ class String { char *s; public: String(); String(const char* n); String(const String& ref); ~String(); void printString(); char& getChar(int i); }; #endif
&や*を書く位置について char &getChar(int i); ←教科書準拠書式 String(const char *n); ←教科書準拠書式 String(const char* n); ←これでも同じ String(const char * n); ←これでも同じ スペースの位置の違い
コンストラクタ1 String() { s = new char[1]; *s = '\0'; } a s String a; a s \0 オブジェクトの 初期化を自動で やりたいな String() { s = new char[1]; *s = '\0'; } はい, コンストラクタ a \0 s char1個分 確保している点 に注目 String a; 引数のないコンストラクタを デフォルトコンストラクタという 初期値を入れておかないと a.printString() したときエラーになるな… a s
コンストラクタ2 なぜ,いろいろコンストラクタを用意するの? →状況に応じて初期化の仕方を変えたいから b s b s String b(“hello”); String(const char *n) { s = new char[strlen(n) + 1]; strcpy(s, n); } b s e l o \0 h 指定された文字列を 初期値に設定したい b s e l o \0 h
メンバ変数にポインタ変数が含まれているときなど コピーコンストラクタ メンバ変数にポインタ変数が含まれているときなど 単純にオブジェクトを複製すると問題があるときのために,初期化時の複製の仕方を定義するのがコピーコンストラクタ String c = b; String(const String& ref) { s = new char[strlen(ref.s) + 1]; strcpy(s, ref.s); } b s e l o \0 h c c s 同じところを指さないよう注意しなくちゃ b s e l o \0 h
ちゃんと解放してから終了しないとメモリリークする デストラクタ オブジェクトの 後片付けを自動で やりたいな はい, デストラクタ ~String() { delete [] s; } String a; a s \0 ちゃんと解放してから終了しないとメモリリークする
参照 参照を渡さないと 参照を渡すと a s a s ref val s \0 \0 \0 function(String val); 関数等の内部で一時的にオブジェクトの複製が作られる. →オブジェクトが大きいとき処理 が重くなる 参照を渡すと function(const String& ref); 直接,元のオブジェクトを見に行く a \0 s a \0 s ref val s \0 関数等の内部 関数等の内部