抽象クラス1の子クラス抽象クラス2の子クラスの関数

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

抽象クラス1の子クラス抽象クラス2の子クラスの関数

#1

投稿記事 by KK » 3年前

失礼します、c++を使用しているのですが、
抽象クラス1の子クラス抽象クラス2の子クラスの抽象クラス2で定義した関数を、
抽象クラス1のインスタンスで呼び出そうとしたところ、
E2316 'identifier' は 'struct' のメンバーではない
とエラーを吐かれてしまいました。

この場合、抽象クラス1のインスタンスで呼び出す方法はありますでしょうか?
またない場合は、どのような方法がありますでしょうか?

文面だけではわかりにくいのでサンプルコードを置いておきます。

コード:

class One{
public:
virtual void A = 0;
};

コード:

class Two : public one{
public:
virtual void B = 0;
};

コード:

class Three : public two{
public:
virtual void B(){/*略*/};
};

コード:

//制御部分
void Control(){
One* one;
Three three;
one = &three;

one->B();//問題の部分
}

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#2

投稿記事 by YuO » 3年前

なぜそういうことをしたいのでしょうか。

One*型の変数であると宣言していることは,その変数はOne*型として取り扱う,と言っていることになります。
Bという関数はOneというクラスに存在しないのですから,当然使えません。

Two*型にdynamic_castすることで使えるようにはなりますが,もっと手前の話として,
  • そもそもOne*として取り扱うのが間違い
  • そもそもOneにBという関数がないのが間違い
  • そもそもBを呼び出そうとしているのが間違い
のどれかだと思います。

inemaru
記事: 108
登録日時: 3年前

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#3

投稿記事 by inemaru » 3年前

こんな感じでどうですか?
ThreeをOneに代入するには
OneにBを呼び出すための定義が必要です。
コンパイルエラーする場合は、override キーワードを削除してください

・抽象クラスを使用する場合

コード:

#include <iostream>

struct One {
	virtual ~One(){};
	virtual void A(){};
	virtual void B(){}; // 定義が必要
};

struct Two : public One {
	virtual void B() override {
		std::cout << "Two::B" << std::endl;
	}
};

struct Three : public Two {
	virtual void B() override {
		std::cout << "Three::B" << std::endl;
	}
};

int main(void)
{
	Three three;
	One& one = three;

	one.B();

	rewind(stdin), getchar();
	return 0;
}
・純粋仮想関数を使用する場合

コード:

#include <iostream>

struct One {
	virtual ~One(){};
	virtual void A() = 0;
	virtual void B() = 0; // 定義が必要
};

struct Two	: public One {
	virtual void A() override {}
	virtual void B() override {
		std::cout << "Two::B" << std::endl;
	}
};

struct Three	: public Two {
	virtual void A() override {}
	virtual void B() override {
		std::cout << "Three::B" << std::endl;
	}
};

int main(void)
{
	Three three;
	One& one = three;

	one.B();

	rewind(stdin), getchar();
	return 0;
}

hide

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#4

投稿記事 by hide » 3年前

質問者がどうしたいのかはわかるけど、何がしたいのかがわからないのでコードを返してもしょうがない感じはしますね。
抽象クラス というのは抽象的なクラスを表しますので、インスタンスにしません。

関数を呼びたい、とかではなくもっともっと具体的に、何をするためにその設計になったのかを書いて欲しいですね。

hide

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#5

投稿記事 by hide » 3年前

抽象クラス自体をインスタンス化してるわけではないのか、でも文章的にはそういうことになってて変な感じ。
AをBが継承している設計で Bのインスタンスを Aの型の変数に入れたとしても、
Aクラスのインスタンスと呼ぶべきではないです。

結局のところやっぱりなぜ親の型に代入してから子の関数を使わなければならなくなってしまったのかの、
具体的な理由を聞いた方が良さそうです。

inemaru
記事: 108
登録日時: 3年前

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#6

投稿記事 by inemaru » 3年前

「何をしようとしてそのような実装にするのか」は
今回は気にせずに回答しています。
(Any型やObject型の類でオブジェクト指向としては破綻していない為)

目的によって、それが適した方法なのかという論点では
hideさんの言う通りで、完全に外視状態です。

なので、
以下に、考え方を書きます。

「物」を継承した「生き物」
「生き物」を継承した「人」
「物」は「人」か?

と考えたとき、
「物」:One
「生き物」:Two
「人」:Three
でマップできる気がします。

「物」にない機能を「人」が持っている状況で
「物」を使って「人」の機能を使用することを許可するのか?

許可するのであれば、
・何らかの方法で「物」に「人」の機能を持たせる
 (「物」は「人」の機能を持っているかもしれない)
・「物」を「人」として扱う
 (「物」が「人」だと分かりきっているので「人」として扱える)
と言った方法があります。

前者は、先ほどの自分の回答
後者は、YuOさんのdynamic_castの話
が該当します。

KK

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#7

投稿記事 by KK » 3年前

こんな拙いプログラマーのプログラムを熟考していただきありがとうございます。
私はゲームプログラミングをしていて
それぞれ
Oneがキャラクター
Twoが敵
Threeが具体的な敵(ボスやザコなど)

に該当するようなプログラムを組もうとしてます。
キャラクターには敵以外にも、
プレイヤーなども含めるため2つ抽象クラスができるような
状況になってしまいました。

キャラクタークラス(One)にはキャラクター全般に該当する
関数(描画や移動など)があり、それがAに該当します。

敵クラス(Two)にはプレイヤーにはない
一定時間経つと出現する関数を付け足したく
それがTwoクラスのBに該当します。

以上簡単なクラスの説明でした。

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#8

投稿記事 by YuO » 3年前

基本的に,C++において,宣言した範囲で出来ないことはするな,です。

今回の場合,敵のみが行う事があるのであれば,Two*なりThree*なりで取り扱うべきです。
なぜ,One*として取り扱う必要があるのでしょうか。
オフトピック
単純に,std::vector<One *>があるからといって,std::vector<Two *>を作ってはいけないわけではないし,
一つのインスタンスへのポインタを両方に入れて良いのだから,Two *として取り扱わない理由が無い。

KK

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#9

投稿記事 by KK » 3年前

Oneで扱えたらひとまとめに出来て楽になるかなという僕の横着でした。
今回の質問でオブジェクト指向に関してまだまだ甘いことが分かりましたので
精進します。
何はともあれ、質問に回答していただいた皆様、本当にありがとうございました。

hide

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#10

投稿記事 by hide » 3年前

oneとして扱えたら楽というのは間違っていません。
ただし、それは同じ関数を呼べばOKであるから、という前提の上に成り立ちます。
なのでoneとして扱った上でthreeの関数を呼んでしまうのはまずかったですね。

私が実装するとしたら、oneに共通の関数のUpdateでも宣言しておいて、毎フレーム呼べば
一定時間経つと出現する という条件を自分で確認することができるので、
threeのUpdateから現れるための関数を自分自身で呼べばいいかと思います。
なので、three側で勝手にprivateで実装してしまえばOKだと思いました。

ゲームの細かいところを知っているわけではないので、設計の例でしかありませんが。

inemaru
記事: 108
登録日時: 3年前

Re: 抽象クラス1の子クラス抽象クラス2の子クラスの関数

#11

投稿記事 by inemaru » 3年前

ゲームプログラミングにおいては、
共通で扱える関数があるものを抽象化するのが効率的です。
特に、パフォーマンス的な観点からdynamic_castを行うようなことは避けるべきです。
オフトピック
ツール開発や、データ解析において
Object型(共通型)に格納後、ダウンキャスト(dynamic_cast)する手法は使用されるので
(シリアライズ/デシリアライズ、データパーサーでは使用される)
あくまでも、ゲーム開発では避けるべきといった意味です。
なので、今回の場合は、
更新処理といった、
ゲームオブジェクトに共通する基底クラスを作るのが良いと思います。
・初期化
・終了処理
・計算
・更新
は、ゲームオブジェクトとして共通になることが多いので
インターフェースか抽象クラスを用意して継承することで
共通化できます。

Oneをゲームオブジェクトクラスにマップするのであれば、
Oneを持つ配列に格納することは、正しい手法だと思います。
(抽象化するために共通のオブジェクトにまとめるのは有効な手法)

閉鎖

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