Array クラスを作る (コンストラクタ編)

まずはコンストラクタの定義から。

デフォルトコンストラクタ

まずは、デフォルトコンストラクタを定義しましょう。
デフォルトコンストラクタは、オブジェクトを「空配列」として初期化します。

//コンストラクタ (デフォルト)
template<typename T> Array<T>::Array()
: m_nSize(0), m_lpa(NULL) {
}

コピーコンストラクタ

次にコピーコンストラクタを定義します。
コピーコンストラクタの動作を、単純な配列アドレスのコピーではなく、配列データの完全な複製を行うようにすることで、関数の引数・戻り値として配列 (Array オブジェクト) の「値渡し」が可能になります。

//コンストラクタ (コピー)
template<typename T> Array<T>::Array(const Array<T>& a){
if (a.m_nSize){
int nSize =a.m_nSize;
T*  lpa   =new T [nSize];
int i;
for (i=0; i<nSize; ++i) lpa[i] =a.m_lpa[i];
m_nSize =nSize;
m_lpa   =lpa;
}
else {
m_nSize =0;
m_lpa   =NULL;
}
}

ちなみに、要素のコピーに memcpy ではなく代入演算子 = を使用しているのは汎用のためです。(memcpy では、非単純値型オブジェクトを適切にコピーできないことに注意。)


その他のコンストラクタ

デフォルト, コピーの他に、オブジェクトを指定されたサイズの配列として初期化するコンストラクタが欲しいところ。
というわけで、これも実装してみましょう。

//コンストラクタ
template<typename T> Array<T>::Array(int nSize){
assert(nSize >= 0);
if (nSize){
T* lpa =new T [nSize];
m_nSize =nSize;
m_lpa   =lpa;
}
else {
m_nSize =0;
m_lpa   =NULL;
}
}

不適切な使用を防ぐため、このコンストラクタexplict 宣言= しておいた方が良いでしょう。

不適切な使用の例 1: 記号 = を用いた初期化構文の適用

//right: オブジェクトを要素数10の配列として初期化
Array<char> acTestA(10);
//wrong: 数値10を代入しているように見えてしまう
Array<char> acTestB =10;

不適切な使用の例 2: 暗黙の型変換による誤った関数の呼び出し

//Array オブジェクトを引数にとる関数
void foo(const Array<double>& adParam);
int main(){
//wrong: 整数を引数にとる関数のように見えてしまう
foo(10);
return 0;
}