今回はクラスのコピーを禁止する方法を説明します。
複雑では無いので、簡単なサンプルを作ります。
<sample program cpp071-01>
#include <iostream> class Player { public: Player(); Player(const int hp, const int mp); void Show() const; private: int m_hp; int m_mp; }; int main() { Player player1(100, 50); Player player2; player2 = player1; //代入 player2.Show(); Player player3(player2); //コピーコンストラクタ player3.Show(); return 0; } Player::Player() { } Player::Player(const int hp, const int mp) : m_hp(hp), m_mp(mp) { } void Player::Show() const { std::cout << "HP = " << m_hp << " : MP = " << m_mp << std::endl; } |
<実行結果>
HP = 100 : MP = 50 HP = 100 : MP = 50 続行するには何かキーを押してください・・・
Playerクラスを用意しました。
player1を作り、コンストラクタ関数で初期値をセットしています。
player2を作り、player1を代入しました。
問題無くコピー出来ている事が分かります。
player3はコピーコンストラクタを使ってplayer2をコピーして作りました。
これも問題無くコピー出来ています。
この2種類のコピーを禁止するコードを追加します。
<sample program cpp071-02>
#include <iostream>
class Player {
public:
Player();
Player(const int hp, const int mp);
void Show() const;
private:
int m_hp;
int m_mp;
Player(const Player &);
Player& operator=(const Player &);
};
int main()
{
Player player1(100, 50);
Player player2;
player2 = player1;
player2.Show();
Player player3(player2);
player3.Show();
return 0;
}
Player::Player()
{
}
Player::Player(const int hp, const int mp) : m_hp(hp), m_mp(mp)
{
}
void Player::Show() const
{
std::cout << "HP = " << m_hp << " : MP = " << m_mp << std::endl;
}
|
<コンパイル結果>
error C2248: 'Player::operator =': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 note: 'Player::operator =' の宣言を確認してください note: 'Player' の宣言を確認してください error C2248: 'Player::Player': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 note: 'Player::Player' の宣言を確認してください note: 'Player' の宣言を確認してください
コンパイル時にエラーが発生しました。
まず、クラスを見てみます。
private: int m_hp; int m_mp; Player(const Player &); Player& operator=(const Player &); |
privateにコピーコンストラクタと代入演算子のオーバーロードのプロトタイプ宣言を書きました。
これだけでコピーが禁止されます。
privateに書いた変数などは、このクラスの内部でしか使えませんので、main関数など他の場所では使えなくなります。
関数も例外ではありません。
privateに書いた関数は、このクラスの中でしか使えない関数になります。
エラーの内容を見てみましょう。
error C2248: 'Player::operator =': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 |
「=」演算子がprivateなのでアクセス出来ない、と書いてあります。
また、
error C2248: 'Player::Player': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 |
コピーコンストラクタもprivateなのでアクセス出来ません。
前回、関数への値渡しやコンテナへのpushもコピーだと書きました。
実際に確かめてみましょう。
では、関数への値渡しを試します。
何か1つ関数を作って、引数としてクラスを渡してみましょう。
<sample program cpp071-03>
#include <iostream> #include <vector> class Player { public: Player(); Player(const int hp, const int mp); void Show() const; private: int m_hp; int m_mp; Player(const Player &); Player& operator=(const Player &); }; void ShowStatus(const Player player); int main() { Player player(100, 50); ShowStatus(player); return 0; } Player::Player() { } Player::Player(const int hp, const int mp) : m_hp(hp), m_mp(mp) { } void Player::Show() const { std::cout << "HP = " << m_hp << " : MP = " << m_mp << std::endl; } void ShowStatus(const Player player) { player.Show(); } |
<コンパイル結果>
error C2248: 'Player::Player': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 note: 'Player::Player' の宣言を確認してください note: 'Player' の宣言を確認してください
コンパイル時にエラーが発生しました。
関数へ値渡しを行う場合もコピーが行われますが、コピーは禁止されていますのでエラーになりました。
「アドレス渡し」や「参照渡し」であれば問題無く行えます。
次にコンテナへのpushを試してみます。
main関数で「ベクタ」を用意し、クラスをpush_backしてみます。
<sample program cpp071-04>
#include <iostream> #include <vector> class Player { public: Player(); Player(const int hp, const int mp); void Show() const; private: int m_hp; int m_mp; Player(const Player &); Player& operator=(const Player &); }; int main() { Player player(100, 50); std::vector<Player> vecPlayer; vecPlayer.push_back(player); return 0; } Player::Player() { } Player::Player(const int hp, const int mp) : m_hp(hp), m_mp(mp) { } void Player::Show() const { std::cout << "HP = " << m_hp << " : MP = " << m_mp << std::endl; } |
<コンパイル結果>
error C2248: 'Player::Player': private メンバー (クラス 'Player' で宣言されている) にアクセスできません。 note: 'Player::Player' の宣言を確認してください note: 'Player' の宣言を確認してください
コンパイル時にエラーが発生しましたが、長いので最初の3行だけ書きました。
コンテナへのpushは、内部でクラスをコピーしています。
今回はコピーを禁止していますので、エラーになりました。
このようにポインタを持ったクラスを扱う際には、細かい部分まで注意して扱ってください。