クラス
構造体[struct] との違いは以下の通りです:
・キーワードクラス(
public や
private 等)は宣言の中で使用します。
・全クラスのメンバーは指定しない限りデフォルトでアクセス指定子
private を持っています。
・クラスオブジェクトは常に
仮想関数 テーブルを持っています。
・
new 演算子はクラスオブジェクトに適用します。
・クラスはクラスからのみ
継承 する事が出来ます。
クラスと構造体は明示的にコンストラクタとデストラクタを持つ事が出来ます。
明示的にコンストラクタ定義している場合、初期化シーケンスで構造体やクラス変数を初期化する事は出来ません。
サンプルソース:
struct trade_settings {
double limit;
double stop;
uchar slippage;
trade_settings() {
take = 0.0;
stop = 0.0;
slippage= 5;
}
~trade_settings();
};
trade_settings my_set={ 0.0, 0.0, 5};
クリップボードにコピー
コンストラクタ/デストラクタ
コンストラクタは、構造体またはクラスオブジェクトを作成する時に自動的に呼び出され、
通常はクラスメンバを
初期化 する為に使用します。
コンストラクタの名称は、クラス名と一致する必要があります。
コンストラクタには戻り値の型はありません(
void 型指定する事が出来ます)。
定義されたクラスメンバで初期化を必要とするオブジェクト(文字列、動的配列は、コンストラクタの有無に関係なく初期化されます。
各クラスは、パラメータの数や初期化リストによる違いから複数のコンストラクタを持つ事が出来ます。
パラメータ指定が必要なコンストラクタは、パラメトリックコンストラクタと呼ばれます。
パラメータ無しのコンストラクタは、デフォルトコンストラクタと呼ばれます。
クラス内でコンストラクタ宣言されていない場合は、コンパイラはコンパイル時にデフォルトコンストラクタを作成します。
コンストラクタはクラスの記述の中で宣言する事ができ、そのbodyを定義する事が出来ます。
例えばMyDateClassの2つのコンストラクタは次のように定義する事が出来ます。
デフォルトコンストラクタにおいて、クラスの全てのメンバが
TimeCurrent()関数 の値が代入されます。
パラメトリックコンストラクタにおいては、時間の値(m_hour,m_minute,m_second)が入力され、他メンバ(m_year,m_month,m_day)は自動的に現在の日付で初期化されます。
デフォルトコンストラクタは、クラスオブジェクト配列を初期化する時に特別な用途を持っています。
パラメータがデフォルト値を持っているコンストラクタは、デフォルトコンストラクタではありません
サンプルソース:
class CFoo {
datetime m_call_time;
public :
CFoo(const datetime t=0){
m_call_time = t;
};
CFoo(const CFoo &foo){
m_call_time = foo.m_call_time;
};
string ToString(){
return (TimeToString (m_call_time,TIME_DATE|TIME_SECONDS ));
};
};
void OnStart () {
CFoo foo1(TimeCurrent ());
CFoo foo2();
CFoo foo3 = D'2009.09.09' ;
CFoo foo40(foo1);
CFoo foo41 = foo1;
CFoo foo5;
CFoo *pfoo6 = new CFoo();
CFoo *pfoo7 = new CFoo(TimeCurrent ());
CFoo *pfoo8 = GetPointer (foo1);
CFoo *pfoo9 = pfoo7;
Print ("foo1.m_call_time =",foo1.ToString() );
Print ("foo2.m_call_time =",foo2.ToString() );
Print ("foo3.m_call_time =",foo3.ToString() );
Print ("foo40.m_call_time =",foo40.ToString());
Print ("foo5.m_call_time =",foo5.ToString() );
Print ("pfoo6.m_call_time =",pfoo6.ToString());
Print ("pfoo7.m_call_time =",pfoo7.ToString());
Print ("pfoo8.m_call_time =",pfoo8.ToString());
Print ("pfoo9.m_call_time =",pfoo9.ToString());
delete pfoo6;
delete pfoo7;
}
クリップボードにコピー
ユーザー定義のコンストラクタを持つクラスの場合、デフォルトコンストラクタはコンパイラによって生成されません。
これはパラメトリックコンストラクタはクラス内で宣言されている場合を意味します、しかしデフォルトコンストラクタは宣言されていません。
このクラスのクラスオブジェクト配列を宣言する事は出来ません(コンパイラがエラーを返します)。
サンプルソース:
class CFoo {
string m_name;
public :
CFoo(string name) { m_name=name;}
};
void OnStart () {
CFoo badFoo[5];
}
クリップボードにコピー
この例ではCFooクラスは宣言されたパラメトリックコンストラクタを持ちます。
このような場合、コンパイラはコンパイル時に自動的にデフォルトコンストラクタを作成しません。
同時にオブジェクト配列を宣言する時、全ての
オブジェクトが作成され自動的に初期化されている 事が想定されます。
オブジェクトの自動初期化中は、デフォルトコンストラクタを呼び出す必要があります。
しかしデフォルトコンストラクタを明示的に宣言していないと自動的にコンパイラによって生成されない為、オブジェクト生成する事が出来ません。
その為、コンパイラはコンパイル時にエラーを返します。
コンストラクタを使用してオブジェクトを初期化する為の特別な構文があります。
構造体やクラスメンバのコンストラクタ初期化子(初期化の為の特別な構造)は、初期化リストで指定する事が出来ます。
初期化リストはカンマ(,)で区切られた初期化子のリストで、これはコンストラクタの
パラメータリスト の後のコロン(:)の後に来ます。
そして
body の前(中括弧の前)に来ます。
初期化リストにはいくつか要件があります。
・初期化リストはコンストラクタ内でのみ使用できます。
・親メンバは初期化リストで初期化する事は出来ません
・初期化リストは関数の定義(実装)によって続かなければなりません
サンプルソース:
class CPerson {
string m_first_name;
string m_second_name;
public :
CPerson() {Print (__FUNCTION__ );};
CPerson(string full_name);
CPerson(string surname, string name): m_second_name(surname), m_first_name(name) {};
void PrintName(){
PrintFormat ("Name=%s Surname=%s" ,m_first_name,m_second_name);
};
};
CPerson::CPerson(string full_name) {
int pos=StringFind (full_name," ");
if ( pos >= 0 ) {
m_first_name =StringSubstr (full_name,0,pos);
m_second_name=StringSubstr (full_name,pos+1);
}
}
void OnStart () {
CPerson people[5];
CPerson Tom="トムソーヤ" ;
CPerson Huck("ハックルベリー" ,"Finn" );
CPerson *Pooh = new CPerson("くまの" ,"プーさん" );
Tom.PrintName();
Huck.PrintName();
Pooh.PrintName();
delete Pooh;
}
クリップボードにコピー
このケースでは、CPersonクラスは次の3つのコンストラクタがあります。
1. このクラスのオブジェクト配列作成出来る明示的なデフォルトコンストラクタ
2. 1つのパラメータを持つコンストラクタ。これはパラメータとして完全な名前を取得し、名前と見つかった空白に応じてセカンドネームに分割します。
3. 初期化リストが含まれている2つのパラメータを持つコンストラクタ。初期化子はm_second_name(姓) と m_first_name(名).
リストを用いた初期化が置換に割り当てられる事に注意してください。個々のメンバーは次のように初期化する必要があります。
クラスメンバ(式のリスト)
クリップボードにコピー
初期化リストでは、メンバーは任意の順番にする事が出来ます。
しかしクラスの全てのメンバは、メンバの定義順に従って初期化されます。
これは上記サンプルソースの第三のコンストラクタ(初期化リストを持つコンストラクタ)が良い例です。
1番目に定義されたメンバ(m_first_name)が最初に初期化され、その後に2番目に定義されたメンバ(m_second_name)が初期化されます。
デフォルトコンストラクタは基本クラスで宣言されていないと同時に、パラメータを有する1つ以上のコンストラクタを宣言している場合は、
常に初期化リスト内の基本クラスのコンストラクタの1つを呼び出す必要があります。
これは初期化リストのどこにあるかに関係無く、オブジェクト初期化時に最初に呼び出されます。
上記のサンプルソースでは、barオブジェクトを作成する時にデフォルトコンストラクタCBar()を呼び出します。
ここで、最初に親CFooのコンストラクタが呼び出され、その後m_memberクラスメンバのコンストラクタが来ます。
デストラクタはクラスのオブジェクトが破壊された時に自動的に呼び出される特殊な関数です。
デストラクタはクラス名の前にチルダ(~)を記述します。
デストラクタの有無に関わらず、文字列や動的配列のオブジェクトは解放されます。
デストラクタが有る場合、これらのアクションはデストラクタを呼び出した後に実行されます。
デストラクタは
virtual キーワード宣言の有無に関わらず常にvirtualです。
クラスメソッドの定義
クラス関数メソッドは、クラス内及びクラス外の両方に定義する事が出来ます。
メソッドがクラス内で定義されている場合は、そのbodyはメソッド定義の右に来ます。
SetRightBorder(int border)関数からDraw()関数までは、CTetrisShapeクラス内部で直接定義されています。
CTetrisShape()コンストラクタと、CheckDown(int& pad_array[]), CheckLeft(int& side_row[]) , CheckRight(int& side_row[])メソッドは、
クラス内でのみ宣言されていますが、未だ定義はされていません。
これらの関数の定義するには更なるコードが必要です。
クラス外でメソッドを定義する為には、
スコープ解決演算子 を使用し、クラス名はスコープとして使用します。
サンプルソース:
#define SHAPE_SIZE 10
void CTetrisShape::CTetrisShape() {
m_type = 0;
m_ypos = 0;
m_xpos = 0;
m_xsize = SHAPE_SIZE;
m_ysize = SHAPE_SIZE;
m_prev_turn = 0;
m_turn = 0;
m_right_border = 0;
}
bool CTetrisShape::CheckDown(int & pad_array[])
{
int i,xsize = m_xsize/SHAPE_SIZE;
for (i=0; i < xsize; i++) {
if (m_ypos+m_ysize >= pad_array[i]) {
return ( false );
}
}
return ( true );
}
クリップボードにコピー
アクセス指定子(public, protected, private)
新しいクラスを作成する時は、外部からのメンバアクセス制限するをお勧めします。
private 又は protected キーワードを使用する事で制限する事が出来ます。
この場合、隠されたデータは同じクラスの関数メソッドからのみアクセス可能になります。
protectedキーワードを使用した場合、隠されたデータとクラスメソッドは
継承 クラスからアクセス出来ます
クラスのメンバやメソッドを完全にオープンにしてアクセス制限しない場合は、publicキーワードを使用します。
サンプルソース:
class CTetrisField {
private :
int m_score;
int m_ypos;
int m_field[FIELD_HEIGHT][FIELD_WIDTH];
int m_rows[FIELD_HEIGHT];
int m_last_row;
CTetrisShape *m_shape;
bool m_bover;
public :
void CTetrisField() { m_shape=NULL ; m_bover=false ; }
void Init();
void Deinit();
void Down();
void Left();
void Right();
void Rotate();
void Drop();
private :
void NewShape();
void CheckAndDeleteRows();
void LabelOver();
};
クリップボードにコピー
public指定子の後(次のアクセス指定子前まで)に宣言されたクラスメンバとメソッドは、クラスオブジェクトへの参照で使用出来ます。
この例では、CTetrisField()関数からDrop()関数までが対象になります。
private指定子の後(次のアクセス指定子前まで)に宣言されたメンバは、このクラスのメンバ関数でのみ使用出来ます。
アクセス指定子は必ずコロン(:)で終了し、クラス定義内で何度も適用する事が出来ます。
基本クラスのメンバへのアクセスは、派生クラスの
継承 の際に再定義する事が出来ます。