C++における、抽象クラスについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Bone

C++における、抽象クラスについて

#1

投稿記事 by Bone » 12年前

短期間に2度も質問してしまいますが、C++の仮想クラスにおける、その仮想クラスの子クラスに仮想クラスに含まれていないメソッドをどうよびだせばいいですか?

コード:

class ITest{
public:
 virtual void Updata() = 0;
 virtual ~ITest(){}
};

class CTest:public ITest{
public:
 virtual Updata(){}override;
 Draw();
};

int main(){
 ITest *ptr;
 ptr = new CTest();
 ptr->Updata();
 (CTest*)ptr->Draw(); /*エラーがでる。描画関数を呼び出したい*/
}
この場合、VCを使ってるのですが、エラーが出ます。
これを実現させる方法はあるのでしょうか?
開発環境は、VC++2010、Windowsです。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: C++における、抽象クラスについて

#2

投稿記事 by みけCAT » 12年前

このように書き換えると、Ideone.comのC++ 4.8.1でコンパイルを通すことができました。

コード:

#define override

class ITest{
public:
 virtual void Updata() = 0;
 virtual ~ITest(){}
};
 
class CTest:public ITest{
public:
 virtual void Updata(){}override;
 void Draw();
};
 
int main(){
 ITest *ptr;
 ptr = new CTest();
 ptr->Updata();
 ((CTest*)ptr)->Draw(); /*エラーがでる。描画関数を呼び出したい*/
}

void CTest::Draw() {}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1892
登録日時: 13年前
連絡を取る:

Re: C++における、抽象クラスについて

#3

投稿記事 by usao » 12年前

オフトピック
ダウンキャストしないといけない場面なのでしょうか

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

Re: C++における、抽象クラスについて

#4

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

ダウンキャスト(親→子)は本来違う子をキャストしてしまう可能性があり危険なので出来るだけ避けるのが鉄則です。
なので、ダウンキャストが起こる設計自体を見なおしたほうが良いですね。

※ せっかくの抽象化を無意味にしてしまうので、オブジェクト指向的にも良くないと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Bone

Re: C++における、抽象クラスについて

#5

投稿記事 by Bone » 12年前

みけCAT さんが書きました:このように書き換えると、Ideone.comのC++ 4.8.1でコンパイルを通すことができました。

コード:

#define override

class ITest{
public:
 virtual void Updata() = 0;
 virtual ~ITest(){}
};
 
class CTest:public ITest{
public:
 virtual void Updata(){}override;
 void Draw();
};
 
int main(){
 ITest *ptr;
 ptr = new CTest();
 ptr->Updata();
 ((CTest*)ptr)->Draw(); /*エラーがでる。描画関数を呼び出したい*/
}

void CTest::Draw() {}
回答ありがとうございます!
なるほど、ダウンキャストする場合、ちゃんと括弧につけなければならないんですね!

Bone

Re: C++における、抽象クラスについて

#6

投稿記事 by Bone » 12年前

usao さんが書きました:
オフトピック
ダウンキャストしないといけない場面なのでしょうか
そういうことになりますね。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: C++における、抽象クラスについて

#7

投稿記事 by みけCAT » 12年前

Bone さんが書きました:なるほど、ダウンキャストする場合、ちゃんと括弧につけなければならないんですね!
ダウンキャストは関係ありません。
同様の原因でエラーになる例を示します。
コードはC言語ですが、C++でも同じだと思います。

コード:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
	int a,b;
} hoge;

int comp(const void* x,const void* y) {
#if 0
	/* エラー */
	if((const hoge*)x->a > (const hoge*)y->a) return 1;
	if((const hoge*)x->a < (const hoge*)y->a) return -1;
#else
	/* OK */
	if(((const hoge*)x)->a > ((const hoge*)y)->a) return 1;
	if(((const hoge*)x)->a < ((const hoge*)y)->a) return -1;
#endif
	return 0;
}

int main(void) {
	hoge h[10];
	int i;
	for(i=0;i<10;i++) {
		h[i].a=(i*3)%10;
		h[i].b=i;
	}
	for(i=0;i<10;i++) {
		printf("%d %d\n",h[i].a,h[i].b);
	}
	puts("-----------");
	qsort(h,10,sizeof(hoge),comp);
	for(i=0;i<10;i++) {
		printf("%d %d\n",h[i].a,h[i].b);
	}
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Bone

Re: C++における、抽象クラスについて

#8

投稿記事 by Bone » 12年前

softya(ソフト屋) さんが書きました:ダウンキャスト(親→子)は本来違う子をキャストしてしまう可能性があり危険なので出来るだけ避けるのが鉄則です。
なので、ダウンキャストが起こる設計自体を見なおしたほうが良いですね。

※ せっかくの抽象化を無意味にしてしまうので、オブジェクト指向的にも良くないと思います。
なるほど、やはりダウンキャストは使うべきでは、ないのですね。
いまいち、仮想クラスを用いて、ポリモーフィズムを使う場面というのがわからず、ゲームプログラミングの館においての、シーン変更などの実用例を見ても、あまりぴんと来ません。
少し、疑問におもっていることなのですが、

コード:

#include <iostream>
class ITest{
public:
 virtual void Updata() = 0;
 virtual ~ITest(){}
};
 
class CTest1:public ITest{

class ITest{
public:
 virtual void Updata() = 0;
 virtual ~ITest(){}
};
 
class CTest1:public ITest{
public:
 virtual void Updata()override{}
 void Draw(){};
};

class CTest2:public ITest{
public:
 virtual void Updata() override{
  //Draw();
 }
 void Draw();
};

int main(){
 ITest *ptr[2];
 ptr[0] = new CTest1();
 ptr[1] = new CTest2();
 for(int i = 0; i < 2; i++){
  ptr[i]->Updata();
 } 
}
このような使い方をした場合外部参照でエラーになります。
この場合においても、やはり、ダウンキャストしなければならないのでしょうか?

Bone

Re: C++における、抽象クラスについて

#9

投稿記事 by Bone » 12年前

みけCAT さんが書きました:
Bone さんが書きました:なるほど、ダウンキャストする場合、ちゃんと括弧につけなければならないんですね!
ダウンキャストは関係ありません。
同様の原因でエラーになる例を示します。
コードはC言語ですが、C++でも同じだと思います。

コード:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
	int a,b;
} hoge;

int comp(const void* x,const void* y) {
#if 0
	/* エラー */
	if((const hoge*)x->a > (const hoge*)y->a) return 1;
	if((const hoge*)x->a < (const hoge*)y->a) return -1;
#else
	/* OK */
	if(((const hoge*)x)->a > ((const hoge*)y)->a) return 1;
	if(((const hoge*)x)->a < ((const hoge*)y)->a) return -1;
#endif
	return 0;
}

int main(void) {
	hoge h[10];
	int i;
	for(i=0;i<10;i++) {
		h[i].a=(i*3)%10;
		h[i].b=i;
	}
	for(i=0;i<10;i++) {
		printf("%d %d\n",h[i].a,h[i].b);
	}
	puts("-----------");
	qsort(h,10,sizeof(hoge),comp);
	for(i=0;i<10;i++) {
		printf("%d %d\n",h[i].a,h[i].b);
	}
	return 0;
}
つまり
((Player*)ptr)のような形にして、アローを飛ばさないと、ptrだけのアドレスが飛ばされているということでしょうか?

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

Re: C++における、抽象クラスについて

#10

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

コピペをミスっていませんか? このコードですよね?

コード:

#include <iostream>
class ITest {
public:
	virtual void Updata() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Updata()override {}
	void Draw() {};
};

class CTest2: public ITest {
public:
	virtual void Updata() override {
		//Draw();
	}
	void Draw();
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Updata();
	}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: C++における、抽象クラスについて

#11

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

とりあえず、これじゃダメなのでしょうか? ダメなら理由を教えて下さい。

コード:

#include <iostream>
class ITest {
public:
	virtual void Updata() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Updata() { std::cout << "CTest1 Updata()" << std::endl;  }
	void Draw() { std::cout << "CTest1 Draw()" << std::endl; };
};

class CTest2: public ITest {
public:
	virtual void Updata() { std::cout << "CTest2 Updata()" << std::endl;  }
	void Draw() { std::cout << "CTest2 Draw()" << std::endl; };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Updata();
		ptr[i]->Draw();
	}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Bone

Re: C++における、抽象クラスについて

#12

投稿記事 by Bone » 12年前

softya(ソフト屋) さんが書きました:とりあえず、これじゃダメなのでしょうか? ダメなら理由を教えて下さい。

コード:

#include <iostream>
class ITest {
public:
	virtual void Updata() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Updata() { std::cout << "CTest1 Updata()" << std::endl;  }
	void Draw() { std::cout << "CTest1 Draw()" << std::endl; };
};

class CTest2: public ITest {
public:
	virtual void Updata() { std::cout << "CTest2 Updata()" << std::endl;  }
	void Draw() { std::cout << "CTest2 Draw()" << std::endl; };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Updata();
		ptr[i]->Draw();
	}
}
すみません、先ほどのは//Draw()ではなく、Draw()です。
紛らわしいネーミングにしていますが、実際は、Updata()の中に、updataの処理(関数)を入れようと思っていました。
実行した結果、外部参照にあったため、コンソールで確認したときのコードを使いました。
やはり、別の方法を考えるべきでしょうか?

Bone

Re: C++における、抽象クラスについて

#13

投稿記事 by Bone » 12年前

だめであるわけでは有りません。
ただ、確認したく思いました。
言葉足らずですみません。

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

Re: C++における、抽象クラスについて

#14

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

やはり、やりたいことが分かりません。
コードで書いてくださいね。

これでもないのでしょうか?

コード:

#include <iostream>
class ITest {
public:
	virtual void Updata() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Updata() { std::cout << "CTest1 Updata()" << std::endl;  func(); }
	void Draw() { std::cout << "CTest1 Draw()" << std::endl; };
	void func() { std::cout << "CTest1 func()" << std::endl;  };
};

class CTest2: public ITest {
public:
	virtual void Updata() { std::cout << "CTest2 Updata()" << std::endl;  funcx(); }
	void Draw() { std::cout << "CTest2 Draw()" << std::endl; };
	void funcx() { std::cout << "CTest2 funcx()" << std::endl;  };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Updata();
		ptr[i]->Draw();
	}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
Tatu
記事: 445
登録日時: 15年前
住所: 北海道

Re: C++における、抽象クラスについて

#15

投稿記事 by Tatu » 12年前

本題には関係ありませんが
updataってupdate(アップデート,最新にする)じゃないんですか?

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

Re: C++における、抽象クラスについて

#16

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

あっupdataじゃなくupdateっぽいですね。
すいません見過ごしてました。
※ こういうミスに気づきにくい softya(ソフト屋)です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Bone

Re: C++における、抽象クラスについて

#17

投稿記事 by Bone » 12年前

softya(ソフト屋) さんが書きました:やはり、やりたいことが分かりません。
コードで書いてくださいね。

これでもないのでしょうか?

コード:

#include <iostream>
class ITest {
public:
	virtual void Updata() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Updata() { std::cout << "CTest1 Updata()" << std::endl;  func(); }
	void Draw() { std::cout << "CTest1 Draw()" << std::endl; };
	void func() { std::cout << "CTest1 func()" << std::endl;  };
};

class CTest2: public ITest {
public:
	virtual void Updata() { std::cout << "CTest2 Updata()" << std::endl;  funcx(); }
	void Draw() { std::cout << "CTest2 Draw()" << std::endl; };
	void funcx() { std::cout << "CTest2 funcx()" << std::endl;  };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Updata();
		ptr[i]->Draw();
	}
}
やりたい言葉を簡潔に述べますと、敵と味方の共通点を多様性を用いて実行します。
が、敵クラス、味方クラスは共通メソッド以外にもそれぞれのメソッドを持っています。
敵クラスの更新と味方クラスの更新で、おのおののメソッドをおのおののupdate内で利用したいと思います。
そう思いまして、先ほどのコードを書きました。
コードを今拝見したのですが、overrideは必要なしなんでしょうか?
このあたりの理解がまだ深くないため、初歩的なことでもうしわけないです。

Bone

Re: C++における、抽象クラスについて

#18

投稿記事 by Bone » 12年前

Tatu さんが書きました:本題には関係ありませんが
updataってupdate(アップデート,最新にする)じゃないんですか?
いままで、updataだと、勘違いしてました・・・
updateに書き換えていきます・・・

Bone

Re: C++における、抽象クラスについて

#19

投稿記事 by Bone » 12年前

すみません、初歩的ミスをしていて、修正したところ、外部参照にはなりませんでした。
お騒がせしました。

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

Re: C++における、抽象クラスについて

#20

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

すいません雑でした。 overrideは付けた方がミスが減らせると思います。

コード:

#include <iostream>
class ITest {
public:
	virtual void Update() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Update() override { std::cout << "CTest1 Update()" << std::endl;  func(); }
	virtual void Draw() override { std::cout << "CTest1 Draw()" << std::endl; };
	void func() { std::cout << "CTest1 func()" << std::endl;  };
};

class CTest2: public ITest {
public:
	virtual void Update() override { std::cout << "CTest2 Update()" << std::endl;  funcx(); }
	virtual void Draw() override { std::cout << "CTest2 Draw()" << std::endl; };
	void funcx() { std::cout << "CTest2 funcx()" << std::endl;  };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Update();
		ptr[i]->Draw();
	}
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Bone

Re: C++における、抽象クラスについて

#21

投稿記事 by Bone » 12年前

softya(ソフト屋) さんが書きました:すいません雑でした。 overrideは付けた方がミスが減らせると思います。

コード:

#include <iostream>
class ITest {
public:
	virtual void Update() = 0;
	virtual void Draw() = 0;
	virtual ~ITest() {}
};

class CTest1: public ITest {
public:
	virtual void Update() override { std::cout << "CTest1 Update()" << std::endl;  func(); }
	virtual void Draw() override { std::cout << "CTest1 Draw()" << std::endl; };
	void func() { std::cout << "CTest1 func()" << std::endl;  };
};

class CTest2: public ITest {
public:
	virtual void Update() override { std::cout << "CTest2 Update()" << std::endl;  funcx(); }
	virtual void Draw() override { std::cout << "CTest2 Draw()" << std::endl; };
	void funcx() { std::cout << "CTest2 funcx()" << std::endl;  };
};

int main() {
	ITest *ptr[2];
	ptr[0] = new CTest1();
	ptr[1] = new CTest2();
	for( int i = 0; i < 2; i++ ) {
		ptr[i]->Update();
		ptr[i]->Draw();
	}
}
コピペして、実行してみました!
これが出来るのであれば、何とかなりそうです!
回答してくださったかたがた、ありがとうございました!

Mana

Re: C++における、抽象クラスについて

#22

投稿記事 by Mana » 12年前

敵と味方の共通点ってことならこういうことではないのかな?

コード:

#include <iostream>
class ITest {
public:
    virtual void Update() = 0;
    virtual void Draw() = 0;
    virtual ~ITest() {}
};

class CPlayerBase : public ITest {
public:
	virtual void Func() { std::cout << "CPlayerBase Func()" << std::endl; }
};

class CEnemyBase : public ITest {
public:
	virtual void Func() { std::cout << "CEnemyBase Func()" << std::endl; }
};
 
class CPlayer1 : public CPlayerBase {
public:
    virtual void Update() override { std::cout << "CPlayer1 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CPlayer1 Draw()" << std::endl; };
};

class CEnemy1: public CEnemyBase {
public:
    virtual void Update() override { std::cout << "CEnemy1 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CEnemy1 Draw()" << std::endl; };
};

class CEnemy2: public CEnemyBase {
public:
    virtual void Update() override { std::cout << "CEnemy2 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CEnemy2 Draw()" << std::endl; };
};
 
int main() {
    ITest *ptr[3];
    ptr[0] = new CPlayer1();
    ptr[1] = new CEnemy1();
    ptr[2] = new CEnemy2();
    for( int i = 0; i < 3; i++ ) {
        ptr[i]->Update();
        ptr[i]->Draw();
    }
    return 0;
}

Bone

Re: C++における、抽象クラスについて

#23

投稿記事 by Bone » 12年前

Mana さんが書きました:敵と味方の共通点ってことならこういうことではないのかな?

コード:

#include <iostream>
class ITest {
public:
    virtual void Update() = 0;
    virtual void Draw() = 0;
    virtual ~ITest() {}
};

class CPlayerBase : public ITest {
public:
	virtual void Func() { std::cout << "CPlayerBase Func()" << std::endl; }
};

class CEnemyBase : public ITest {
public:
	virtual void Func() { std::cout << "CEnemyBase Func()" << std::endl; }
};
 
class CPlayer1 : public CPlayerBase {
public:
    virtual void Update() override { std::cout << "CPlayer1 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CPlayer1 Draw()" << std::endl; };
};

class CEnemy1: public CEnemyBase {
public:
    virtual void Update() override { std::cout << "CEnemy1 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CEnemy1 Draw()" << std::endl; };
};

class CEnemy2: public CEnemyBase {
public:
    virtual void Update() override { std::cout << "CEnemy2 Update()" << std::endl;  Func(); }
    virtual void Draw() override { std::cout << "CEnemy2 Draw()" << std::endl; };
};
 
int main() {
    ITest *ptr[3];
    ptr[0] = new CPlayer1();
    ptr[1] = new CEnemy1();
    ptr[2] = new CEnemy2();
    for( int i = 0; i < 3; i++ ) {
        ptr[i]->Update();
        ptr[i]->Draw();
    }
    return 0;
}
回答拝見しました!
感覚的にはこんなかんじです!
ありがとうございます!

閉鎖

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