C++のオーバライド

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
ひよこ
記事: 25
登録日時: 9年前

C++のオーバライド

#1

投稿記事 by ひよこ » 9年前

おはようございます。

C++での質問です。
オーバーライドを使いたいのですが
予想通りに動きません。これはどうしてなのでしょうか?

予想
最終的に
printf("%d\n",saList[1].Get());
の行動が
printf("%d\n",SaList[1]->Get());
と同じにしたいのですが。
2回目のsaList.Getでsbと表示したい。

コード:

class sa{
public:
	int a;
	virtual int Get(){
		printf("sa\n");
		return a;
	}
	sa(){a=0;}
};

class sb:public sa{
	int b;
public:
	int Get(){
		printf("sb\n");
		return b;
	}
	sb(){a=10,b=20;}
};

sa *SaList[2] = {
	//{new sa},
	//{new sb},
};

//クラスをまとめるリスト
sa *saList;

sa Make_StateList2(sa List[]){
	saList = List;
	return List[0];
}

int main(){
	//クラスのを作成(アドレスとびとび)
	SaList[0] = new sa();
	SaList[1] = new sb();
	
	//そのままの状態を表示
	printf("%d\n",SaList[0]->Get());
	printf("%d\n",SaList[1]->Get());

	//クラスリストに代入(配列にいれて添字でアクセスできるように)
	saList = new sa[2];
	saList[0] = *SaList[0];
	saList[1] = *SaList[1];

	//クラスリストに代入されたものを使う
	printf("%d\n",saList[0].Get());
	printf("%d\n",saList[1].Get());
環境はVC2008Expressです。
よろしくお願いします。

アバター
バグ
記事: 130
登録日時: 9年前
住所: 愛媛県
連絡を取る:

Re: C++のオーバライド

#2

投稿記事 by バグ » 9年前

こんな感じでしょうか?意図に反していたらまたごめんなさい。
それと、newで確保した領域はdeleteで解放するようにしたほうがいいですよ。

コード:

#include <cstdio>

class sa
{
public:
	int a;

	virtual int Get()
	{
		printf("sa\n");
		return a;
	}

	sa()
	{
		a = 0;
	}
};

class sb : public sa
{
private:
	int b;

public:
	int Get()
	{
		printf("sb\n");
		return b;
	}

	sb()
	{
		a=10;
		b=20;
	}
};

int main()
{
	// クラスのを作成(アドレスとびとび)
	sa* SaList[2];
	SaList[0] = new sa();
	SaList[1] = new sb();

	// そのままの状態を表示
	printf("%d\n",SaList[0]->Get());
	printf("%d\n",SaList[1]->Get());

	// クラスリストに代入(配列にいれて添字でアクセスできるように)
	sa** saList;
	saList = new sa*[2];
	saList[0] = SaList[0];
	saList[1] = SaList[1];

	// クラスリストに代入されたものを使う
	printf("%d\n",saList[0]->Get());
	printf("%d\n",saList[1]->Get());

	// 後始末
	delete SaList[0];
	delete SaList[1];
	delete[] saList;

	return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: C++のオーバライド

#3

投稿記事 by softya(ソフト屋) » 9年前

codeタグの使い方が間違っていたので修正しました。投稿前にプレビューして確認して下さいね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

maru
記事: 150
登録日時: 9年前

Re: C++のオーバライド

#4

投稿記事 by maru » 9年前

意図していることがよくわからないのですが、元のプログラムの
saList[1] = *SaList[1];
では sa のオブジェクトに対して sb のオブジェクトを代入してしまっています。
この場合の動作は...
言語仕様に詳しくないので、どうなるのが正しいのかよくわかりません。

もし、意図した動作が、
「派生されたクラスオブジェクトを派生元のクラスオブジェクト配列にいれて、派生元クラスとして動作させたい」
ということであれば、そのような動作をするコードは思いつきません。

あと、sa では a を public にする必要性はないように思われます。
private か protected でいいのでは?

コード:

class sa
{
public:
	sa(int a_=0) : a(a_) {}
	virtual int Get() const
	{
		printf("sa\n");
		return a;
	}
private: // or protected:
	int a;
};

class sb : public sa
{
public:
	sb() : sa(10), b(20) {}
	virtual int Get() const
	{
		printf("sb\n");
		return b;
	}
private:
	int b;
};
としたほうが良いでしょう。

【追記】
コンストラクタで設定した初期値が間違っていましたので、修正しました。
最後に編集したユーザー maru on 2011年7月06日(水) 16:20 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: C++のオーバライド

#5

投稿記事 by softya(ソフト屋) » 9年前

これはあまりやった事はないですが、
saList[1] = *SaList[1];
ではsbクラスの派生情報は消滅するはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
GRAM
記事: 164
登録日時: 9年前
住所: 大阪

Re: C++のオーバライド

#6

投稿記事 by GRAM » 9年前

ひよこ さんが書きました: 予想
最終的に
printf("%d\n",saList[1].Get());
の行動が
printf("%d\n",SaList[1]->Get());
と同じにしたいのですが。
2回目のsaList.Getでsbと表示したい。

コード:

sa *saList;
//まずsaListはsaの並びであり、決してsbが並んでいるわけではない
int main(){
	//クラスのを作成(アドレスとびとび)
	SaList[0] = new sa();
	SaList[1] = new sb();
	
	//そのままの状態を表示
	printf("%d\n",SaList[0]->Get());
	printf("%d\n",SaList[1]->Get());

	//クラスリストに代入(配列にいれて添字でアクセスできるように)
	saList = new sa[2];
	saList[0] = *SaList[0];//ここでSaListの中身が何であれsaにスライスされる
	saList[1] = *SaList[1];//
saListの中身はあくまでsaです。どんなにがんばったとしても。
そのsaにsbを代入した場合、問答無用でsbのsaの部分だけが代入されスライスされます。

結局仮想関数が呼び出されることは未来永劫ありません。
基本的に仮想関数を呼び出すには基底クラスのポインタか参照にアップキャストするしかないということですね。
SaListのほうを使えばいいわけです。

アバター
ひよこ
記事: 25
登録日時: 9年前

Re: C++のオーバライド

#7

投稿記事 by ひよこ » 9年前

皆さん、ありがとうございます。
バグさん動きました。予想通りに動きました。
softyaさん、ありがとうございます。プレビュー確認して半角でないのが原因だと思いますのでこれからは気をつけます。
maruさん,softyaさん,GRAMさん
結局、派生前 =派生後をして派生情報は消滅したのですか。
なるほど、勉強になりました。

皆さんありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る