ページ 11

必ず定義(実装)しなければならない関数

Posted: 2018年4月10日(火) 11:47
by 高山
C++で定義したclass(親)はx,y関数に関するインターフェースを提供するだけで、
それを継承するclass(子)は親classのx関数を実装(実体定義)すれば、
親classのy関数も実装(実体定義)しなければ、
コンパイルエーラになるような仕組みを設計したいですが、
どうすればいいでしょうか。

さらに、『もし子classの実装が親classのx関数を定義しなければ、y関数も定義しなけてもOK』
というような要望もあればどうずれば宜しいでしょうか。


ご教授お願い致します。

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月10日(火) 22:18
by 結城紬
高山 さんが書きました:
6年前
C++で定義したclass(親)はx,y関数に関するインターフェースを提供するだけで、
それを継承するclass(子)は親classのx関数を実装(実体定義)すれば、
親classのy関数も実装(実体定義)しなければ、
コンパイルエーラになるような仕組みを設計したいですが、
どうすればいいでしょうか。
pure virtual にすればOKです。virtual 関数の後ろに = 0 と付けます。

コード:

class 親 {
	virtual T x() = 0;
	virtual T y() = 0;
};
高山 さんが書きました:
6年前
さらに、『もし子classの実装が親classのx関数を定義しなければ、y関数も定義しなけてもOK』
というような要望もあればどうずれば宜しいでしょうか。
親クラスを継承しなければOKです。

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月11日(水) 10:39
by usao
親子関係の存在が前提になっている話に見えるので,
> 親クラスを継承しなければOKです。
というのは違うような…?

とは言え…
「インタフェースを規定する親を継承するけど,実装はしない」子クラスが仮に用意できたとして,
一体どのように使うの想定なのでしょう?

コード:

//子がX,Yを定義しないとコンパイルエラーになる
class Base
{
public:
	virtual void X() = 0;
	virtual void Y() = 0;
};

//デフォルト実装を提供.
//とりあえずコンパイルエラーは回避…
class Base2 : public Base
{
public:
	virtual void X() override { /*何か*/ }
	virtual void Y() override { /*何か*/ }
};
//#上記「何か」の部分には,
//さしさわりの無い実装を書いておくのか,あるいは例外でも投げるのか…??
とかしておいて,子クラスの継承元を{Base, Base2}のどちらにするかを変える,とか…?
(質問文にあるような 「Xなら→Y」 という主従関係みたいな形にはなっていませんが)

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月11日(水) 12:54
by --高山--
皆様
御回答有難うございます!

利用ケースとして、
例えば、classのメソッドにはペアでなければならないものがあるとして
A1(..), A2(...)
B1(..), B2(...)
: :
X1(..), X2(...)

子classによってこれらの関数ペアのうち少なくとも一つを必ず実装しなければならないのですが、
どれを使うか or どれくらい使うかは各子classによって異なります。
各ペア毎に全一つの子classとして対応させるのは大変です(定義の時でも、使う時でも)。

どうすれば良いのでしょうか。
=======
また宜しくお願い致します

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月11日(水) 13:39
by usao
えっと… その子クラス(群)を扱う側のコードはどういう形になるのでしょう?

例えば,ある子クラスが{A1,A2, C1,C2}しか実装していない場合,その子クラスのインスタンスに関してはB1等はコール「されるべきではない」のだろう,と想像するのですが,そういう認識で合っていますか?
そのような話である場合,
子クラスのメソッドをコールする側のコードというのはどうやって{A1,A2,....X1,X2}を適切に呼び分ける(?)想定になっているのでしょうか?

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月11日(水) 20:17
by --高山--
有難うございます。

子classのメソッドをコールする人はその子classを実装するプログラマーであるのを想定しております。
プログラマーは自分がどのメソッドを実装したか、あるいは何をコールすべきかは覚えています。
例えば、自動車会社のプログラマーは決して飛行機関連の関数をコールしないでしょう。

もし、うっかりして自分が定義(実装)していないメソッドをコールしたら、
コンパイルエラーが出されてくれればOKです。
これで開発段階ですぐミス回避できます。

またどうぞ宜しくお願いします。

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月11日(水) 22:03
by 結城紬
高山さん

やはりといいますか、どうもクラスとか継承とかという概念を根本的に誤解されているのではないかと思います。
単に似たようなものをまとめるとか、テンプレート(C++のではなく、一般的な意味として)のようなものと思っていらっしゃるのではないですか。そういった用途に継承を使うのは明らかに間違った使い方です(というのが最初の回答です)。
関数の定義漏れにコンパイルエラーを出すだけが目的なら、継承を使う必要は全くありません。というより、「継承をしない」という選択肢が存在する以上、何の保証をすることもできません。

A, B, ..., X というクラスがあり、それぞれ内部的に 1 か 2 という名前の似たような処理をする。しかし、1, 2 はそれぞれのクラスが内部的に使うだけで、外部の誰からも呼ばれない。
以上の条件から読めることは、A, B, ..., X のクラスは、内部的にやっていることが微妙に似ているが、外部から見ると全く無関係であり、ということはいかなる継承関係も持たないというのが正解です。

usao さんの質問は、「もし継承関係を持つとすれば、1, 2 を呼ぶ外部の存在があるはずなのですが、それは何で、どのように使うのですか?」ということだと思いますが、それを踏まえて高山さんからの回答をお願いできますでしょうか。

Re: 必ず定義(実装)しなければならない関数

Posted: 2018年4月12日(木) 09:58
by usao
> 子classのメソッドをコールする人はその子classを実装するプログラマーであるのを想定しております。
> ...
前提条件として,共通の1つのインタフェース(を規定している親の型でクラス利用側のコードを書くこと)が必要な背景があるのだと
捉えていたのですが,この話の雰囲気だとそういうわけでもない感じでしょうか.
であれば,私も,あえて継承を用いる理由は無いであろうと考えます.

コンパイルエラー側の話に関しても
「子クラスの定義を書いた時点で」エラーが出てほしいという話ではなく.
「コールしたら」なのであれば,特段の工夫(継承とか)は要らないでしょう.

本件において,継承したい理由って何なのでしょう? ということになりそうですね.