|
オブジェクトを作った後に初期化する
次のような、日時を保持する単純なクラスを考えてみます。このクラスはコンストラクタでメンバを初期化します。オブジェクトを作った後でメンバを更新する関数は用意されていません。
// 日時クラス
class CDateTime
{
public:
CDateTime(){}
CDateTime(int year, int month, int date, int hour, int min, int sec) :
m_year(year), m_month(month), m_date(date),
m_hour(hour), m_min(min), m_sec(sec){}
virtual ~CDateTime(){}
int GetYear(){return m_year;}
int GetMonth(){return m_month;}
int GetDate(){return m_date;}
int GetHour(){return m_hour;}
int GetMin(){return m_min;}
int GetSec(){return m_sec;}
private:
int m_year;
int m_month;
int m_date;
int m_hour;
int m_min;
int m_sec;
};
|
このようなクラスでは、次のような方法でメンバの更新をすることができます。
#include "CDateTime.h"
int main(int argc, char *argv[])
{
CDateTime dt1(2006, 10, 17, 20, 0, 0); // (1)コンストラクタでの初期化
CDateTime dt2, dt3; // (2)コンストラクタで初期化しない
dt2 = dt1; // (3)別オブジェクトからのコピー(代入)
dt3 = CDateTime(2006, 10, 18, 6, 0, 0); // (4)一時オブジェクトからのコピー(代入)
return 0;
}
|
(1)は通常の使い方で、コンストラクタでメンバの初期化をしています。(2)はコンストラクタでは初期化していません。
このように、コンストラクタで初期化しないで、オブジェクトを作った後でメンバを更新したいときは、(3)のように他の初期化済みのオブジェクトを代入する方法があります。この方法では、別オブジェクトの内容がそのままビットコピーされます。
この方法では、コピー元である別オブジェクトを用意しないといけません。また、クラスの代入では、メンバがすべてそのままコピーされます。このことによって問題が起こることがあります。
それは、動的に確保したメモリのポインタなどをメンバに持っていて、デストラクタでメモリを開放するような場合です。この場合はコピー元のオブジェクトとコピー先のオブジェクトが同じメモリアドレスのポインタを持つことになるので、2重に開放処理が実行されてしまいます。
これを避けたい場合は、代入演算子のオーバーロードをして、代入時のメモリの扱いを適切に処理する必要があります。
また、(4)のように一時オブジェクトを作ってから、そのオブジェクトの内容をコピー(代入)する方法があります。この場合は、別オブジェクトを用意する必要はありません。この場合気をつけることは、代入が実行された後に、一時オブジェクトのデストラクタが呼び出されるということです。
この場合も、動的メモリのポインタをメンバに持っている場合は、一時オブジェクトのデストラクタですでに開放されてしまうので、代入先のオブジェクトではそのメモリは使えなくなります。
この場合も代入演算子をオーバーロードして、代入時に動的メモリとその内容を複製するなどの処理をする必要があります。
今回の例は、動的メモリを使わない単純なクラスなので、他オブジェクトからのコピーでも、一時オブジェクトからのコピーでも問題はありません。
管理人は結構この"一時オブジェクト"を積極的に使います。(便利なので)
|