class ClassName;
他のクラスの定義などで、その名前だけが必要なときには宣言のみをします。
[template-spec] class [ms-decl-spec] [tag [: base-list ]]
{
member-list
} [declarators];
class (C++) | MSDN
| 修飾子 | |
|---|---|
| private | private (C++) | MSDN |
| protected | protected (C++) | MSDN |
| public | public (C++) | MSDN |
識別子を付けずに定義することで匿名にできます。これは、Cとの互換性のための機能です。匿名クラス型 | MSDN
typedef struct
{
unsigned x;
unsigned y;
} POINT;
class Derived : [virtual] [access-specifier] Base1,
[virtual] [access-specifier] Base2, ...
{
// member list
};
access-specifierは、基底クラス (基本クラス) のメンバに対して適用されるアクセス許可で、省略した場合はprivateとみなされます。派生クラスのアクセス コントロール - メンバー アクセス コントロール (C++) | MSDN
複数の基底クラスを指定した場合は、多重継承 (Multiple Inheritance) と呼ばれます。多重継承 | MSDN
class BaseClass
{
};
class MyClass : public BaseClass
{
};
純粋仮想関数を1つでも含むクラスは抽象クラスであり、派生元となれるだけで、このクラスのオブジェクトを作成することはできません。抽象クラス (C++) | MSDN
class MyClass
{
public:
MyClass();
};
メンバ変数を初期化するための機能です。メンバ変数はコンストラクタの実行前に初期化されることになっているため、これを用いずコンストラクタ内で代入すると初期化された値に上書きすることになります。
class MyClass
{
int a;
int b;
public:
MyClass( int x, int y ) : b( y ), a( x ) // 初期化リスト
{
// a = x; とすると初期化ではなく代入となる
// 初期化リストはb,aの順だが、宣言された順に基づきa,bの順で初期化される
}
};
初期化リストはその変数が宣言された順番で実行されるため、この例ではaの次にbが初期化されます。
初期化リストは、派生クラスのコピーコンストラクタにおいて重要です。これで明示的に基底クラスのコピーコンストラクタを呼ばないと、基底クラスのデフォルト コンストラクタが呼ばれてしまい、結果としてメンバがコピーされなくなります。
class BaseClass
{
int a;
public:
BaseClass( int x ) : a( x ) // 初期化リスト
{
}
};
class SubClass : public BaseClass
{
public:
SubClass( int x ) : BaseClass( x ) // 初期化リスト
{
}
};
class MyClass
{
int a;
int b;
public:
MyClass( const MyClass& obj ) :a( obj.a ), b( obj.b )
{
}
};
コピー コンストラクターとコピー代入演算子 (C++) | MSDN
多重定義された他のコンストラクタは、初期化リストから呼べます。
class MyClass
{
public:
int a;
MyClass(int x)
{
a = x;
}
MyClass() : MyClass(5) // 多重定義されたコンストラクタが先に呼ばれる
{
// ここでMyClass(5) としても、ここで新たなオブジェクトが生成されるだけ
}
};
int main()
{
MyClass myClass(1); // myClass.aは 1となる
MyClass myClass; // myClass.aは 5となる
}
複雑な処理は、共通の初期化用の関数を呼ぶようにします。既定の引数とヘルパ関数 (C++) | MSDN
class MyClass
{
private:
Init(int a)
{
}
public:
MyClass()
{
Init(0)
}
MyClass(int a)
{
Init(a)
}
};
class MyClass
{
public:
~MyClass();
};
デストラクタは、次のいずれかの瞬間に呼び出されます。デストラクターの使用 - デストラクター (C++) | MSDN
class MyClass
{
void Func(); // 宣言
};
// 定義
void MyClass::Func()
{
}
関数のオーバーロードとは、クラス内に同名で引数や戻り値が異なるメンバ関数を複数定義することです。
class MyClass
{
int Func( int a );
int Func( double a );
};
メンバ関数は名前と引数で識別されるため、戻り値の型だけが異なる関数は定義できません。
class MyClass
{
int Func( int a );
double Func( int a ); // エラー
};
組み込みの演算と同じような操作を、クラスに実装できます。
type operator operator-symbol ( parameter-list )演算子のオーバーロード | MSDN
operator double() const { return value; }
ユーザー定義型変換 | MSDN
明示的な型変換を強制するならば、explicitを指定します。
explicit operator double() const { return value; }
仮想関数とは、動的に呼び出す関数が決定されるメンバ関数です。virtualキーワードを指定して宣言することで、仮想関数となります。
class MyClass
{
virtual void Func();
};
継承したクラスでこの仮想関数を実装することで、ポリモーフィズム (Polymorphism / 多態性) を実現できます。
関数のオーバーライドとは、基底クラスの仮想関数より派生クラスのそれを優先する (override) ことです。
純粋仮想関数とは、定義を持たない仮想関数です。仮想関数に、=0という初期設定子を付加することで宣言できます。
class MyClass
{
virtual void Func() = 0;
};
関数宣言にconstを付加することで、その関数ではメンバ変数を変更しないことを表明できます。const のメンバー関数 - const (C++) | MSDN
class MyClass
{
int a = 0;
void Func1() const; // 定数メンバ関数 の宣言
void Func2();
};
void MyClass::Func1() const // 定数メンバ関数 の定義
{
a++; // error C3490: 'a' は const オブジェクトを通じてアクセスされているため変更できません
Func2(); // error C2662: 'void MyClass::Func2(void)': 'const MyClass' から 'MyClass &' へ 'this' ポインターを変換できません。
int x = 0;
x++; // メンバ変数ではないから、ok
}
void MyClass::Func2()
{
a++; // ok
Func1(); // ok
}
staticを付加して宣言することで、静的メンバとなります。
class MyClass
{
public:
// 宣言
static int x; // 静的メンバ変数 (クラス変数)
static void Func(); // 静的メンバ関数 (クラス関数)
};
// 定義
int MyClass::x = 1;
void MyClass::Func()
{
}
静的なメンバであることは宣言で指定し、定義では不要です。
static int MyClass::x; // error C2720: 'MyClass::x': 'static ' ストレージ クラスの指定子が識別子に対して誤って指定されています。 static void MyClass::Func() {} // error C2724: 'MyClass::Func': 'static' をメンバー関数の定義に使ってはいけません。
class MyClass
{
public:
static int x;
static const int y = 2; // 定数の整数のみクラス内で初期化できる
static const double y = 2.0; // エラー コンパイラ エラー C2864 | MSDN
};
int MyClass::x = 10;
void Func()
{
MyClass myClass; // 生成
myClass.x++;
// ブロックから出るときに破棄される
}
void Func()
{
MyClass* myClass = new MyClass(); // 生成
myClass->x++;
...
delete myClass; // 明示的に破棄する
}
new で割り当てたオブジェクトの初期化 - new 演算子 (C++) | MSDN
[::] new [placement] new-type-name [new-initializer] [::] new [placement] ( type-name ) [new-initializer]new 演算子 (C++) | MSDN
void *__cdecl operator new(size_t count);new 演算子 (CRT) | MSDN
void *__cdecl operator new[](size_t count);演算子 new(CRT) | MSDN
[::] delete cast-expression [::] delete [ ] cast-expressiondelete 演算子 (C++) | MSDN
オブジェクトが配列を参照している場合には、delete []とします。これをdeleteとすると、予期せぬ結果をもたらします。
int* p = new int[10]; ... delete [] p;
MyClass* myClass = new MyClass(); myClass++; delete myClass;
--------------------------- Microsoft Visual C++ Runtime Library --------------------------- Debug Assertion Failed! Program: ***.exe File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp Line: 888 Expression: _CrtIsValidHeapPointer(block)
int* p = new int[3]; p[3] = 1;
CRTのデバッグ ヒープ関数では、次のように検出されます。
--------------------------- Microsoft Visual C++ Runtime Library --------------------------- Debug Error! Program: ***.exe HEAP CORRUPTION DETECTED: after Normal block (#**) at 0x***. CRT detected that the application wrote to memory after end of heap buffer.
境界を越えた位置、たとえばこの例ではp[4]やp[-2]の位置への書き込みは、このようには検出されません。
テスト環境でデバッグしたとき、次のように検出されることもあります。
--------------------------- Microsoft Visual C++ Runtime Library --------------------------- Debug Assertion Failed! Program: ...XTENSIONS\MICROSOFT\TESTWINDOW\vstest.executionengine.x86.exe File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp Line: 892 Expression: is_block_type_valid(header->_block_use)
また0xc0000374で終了するときも、ヒープの破壊が原因のことがあります。ヒープコラプションのデバッグ手順 ~ 例外 STATUS_HEAP_CORRUPTION (0xc0000374) - Web/DB プログラミング徹底解説
プログラム '[***] ***.exe' はコード -1073740940 (0xc0000374) で終了しました。