DATE : 2006/09/27 (Wed)
コピーコンストラクタを用意したり代入演算子のオーバーロードを行うことで、ポインタをメンバに持つクラスでも安全にオブジェクトをコピーしたり代入したりできるようになります。
しかし、場合によってはコピーや代入を禁止したい場合もあります。例えば、メンバの依存関係が複雑で安全にコピー、代入ができない場合などが挙げられます。「○○クラスはコピー、代入禁止」と約束事を決めておいても良いのですが、忘れたり見過ごしてしまえば即バクを作りこんでしまうことになります。
そこで、前述のようなオブジェクトがコピーや代入されている文が見つかった場合は、コンパイラがエラーを出すようにします。
具体的には、コピーコンストラクタや代入演算子のオーバーロードを private として宣言します。private として宣言すると、他のクラスからコピーコンストラクタや代入演算子を使えなくなるので、使おうとするとコンパイル時にエラーとなります。
例えば、Line オブジェクトのコピー、代入を禁止するには、次のようにします。
class Line { private : const Point *start; const Point *end; Line(const Line& line); Line& operator=(const Line& line); public : Line(const Point* start, const Point* end); ~Line(); const Point& getStart() const; const Point& getEnd() const; }; Line::Line(const Point* start, const Point* end) : start(start), end(end) { } Line::~Line() { delete this->start; delete this->end; } const Point& Line::getStart() const { return *(this->start); } const Point& Line::getEnd() const { return *(this->end); }
private に移したコピーコンストラクタ、代入演算子のオーバーロードは宣言だけで、実装の方は消去しました。コピー、代入を禁止したので、実装を書く必要がなくなったためです。
上の例では今回の記事用にコピー、代入を禁止しましたが、実際にオブジェクトのコピー、代入を禁止すると、そのオブジェクトの使い勝手が悪くなりがちです。そこで、なるべくはコピーコンストラクタや代入演算子のオーバーロードを用意して、止むを得ない場合に限ってコピー、代入を禁止した方が良いかもしれません。
(ちなみに、フレンドクラスという種類のクラスを使うと、private で宣言されたメンバにもアクセスできます。すると、実装もあった方が良いと思えるかもしれません。しかし、安全にコピー、代入できない理由からコピーコンストラクタや代入演算子のオーバーロードを private 宣言した場合は、実装を用意しても意味がありません)