- PR -

あるクラスの継承を行ったサブクラスのメソッドの呼出しについて

投稿者投稿内容
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-11-14 10:59
現在Sun認定資格Javaプログラマーの勉強をしているのですが、
その中に次のような問題がありました。

【問】下記コードをコンパイルし実行するとどうなるか?

コード:
public class Sample {
 public static void main(String args[]){
 	ClassChild c = new ClassChild();
 	ClassParent p = c;
 	p.getMsgParent();
 	p.getMsgChild();
 }
}

class ClassParent {
	void getMsgParent(){
		System.out.println("Parent");
	}
}

class ClassChild extends ClassParent{
	void getMsgChild(){
		System.out.println("Child");
	}
}


正解はmain()での p.getMsgChild()
が原因でコンパイルエラーが起こると言うものでした。

たしかに実際プログラムを組み実行させてみましたら、
問題の通りコンパイルエラーが発生しました。
 しかし、サブクラスのメソッドを親クラスのメソッドの
オーバーライドとし、main()からp.getMsgChild()の部分を
削除し、
コード:
class ClassChild extends ClassParent{
	void getMsgParent(){
		System.out.println("Child");
	}
}


上記コードはコンパイルエラーにならず、かつ
実行結果は、サブクラスのメソッドが呼び出されます。

コード変更前、後でやっていることは基本的に
サブクラスのメソッドの呼出しだと思うのですが、
通常のメソッドの呼び出しとオーバーライドされた
メソッドの呼出しでどうしてこのような差がでるのか
わかりません。どなたかお分かりの方がいらしましたら
ご教示頂きたいのですが、宜しくお願いします。

m(_ _)mペコリコ お代官さまぁああ(滝涙願)

toppo
ベテラン
会議室デビュー日: 2003/10/28
投稿数: 89
お住まい・勤務地: 東京・池袋
投稿日時: 2003-11-14 11:29
引用:

忍者鳥取県さんの書き込み (2003-11-14 10:59) より:
現在Sun認定資格Javaプログラマーの勉強をしているのですが、
その中に次のような問題がありました。

【問】下記コードをコンパイルし実行するとどうなるか?

コード:

public class Sample {
public static void main(String args[]){
ClassChild c = new ClassChild();
ClassParent p = c;
p.getMsgParent();
p.getMsgChild();
}
}

class ClassParent {
void getMsgParent(){
System.out.println("Parent");
}
}

class ClassChild extends ClassParent{
void getMsgChild(){
System.out.println("Child");
}
}


正解はmain()での p.getMsgChild()
が原因でコンパイルエラーが起こると言うものでした。

たしかに実際プログラムを組み実行させてみましたら、
問題の通りコンパイルエラーが発生しました。
 しかし、サブクラスのメソッドを親クラスのメソッドの
オーバーライドとし、main()からp.getMsgChild()の部分を
削除し、
コード:

class ClassChild extends ClassParent{
void getMsgParent(){
System.out.println("Child");
}
}


上記コードはコンパイルエラーにならず、かつ
実行結果は、サブクラスのメソッドが呼び出されます。

コード変更前、後でやっていることは基本的に
サブクラスのメソッドの呼出しだと思うのですが、
通常のメソッドの呼び出しとオーバーライドされた
メソッドの呼出しでどうしてこのような差がでるのか
わかりません。どなたかお分かりの方がいらしましたら
ご教示頂きたいのですが、宜しくお願いします。

m(_ _)mペコリコ お代官さまぁああ(滝涙願)





どうもtoppoです。

コンパイルエラーになる理由は
ClassParent型にgetMsgChild()メソッドが無い為です。
インスタンスの型がClassChildであっても、
変数の型はClassParentだからです。
言い方を変えると、ClassParentにはgetMsgChild()
というインタフェースは無い。という事です。

忍者鳥取県さんが実行したプログラムでは
getMsgParent()もオーバーライドされているので
コンパイルは通ります。
(ClassParentにはgetMsgParent()というインターフェースがある。)


その上で、インスタンスの型により処理を実行しているわけです。

では。

[ メッセージ編集済み 編集者: toppo 編集日時 2003-11-14 11:52 ]
ぽん
大ベテラン
会議室デビュー日: 2003/05/13
投稿数: 157
投稿日時: 2003-11-14 11:30
引用:

忍者鳥取県さんの書き込み (2003-11-14 10:59) より:
コード:

public class Sample {
public static void main(String args[]){
ClassChild c = new ClassChild();
ClassParent p = c;
p.getMsgParent();
p.getMsgChild();
}
}

class ClassParent {
void getMsgParent(){
System.out.println("Parent");
}
}




問題の引っ掛けに引っかかって、難しく考えすぎているような・・・
問題は「ClassParentにgetMsgChildが宣言されて無いからコンパイルエラーが出る」だけですが。

[追記]
かぶってしまった...

[ メッセージ編集済み 編集者: ぽん 編集日時 2003-11-14 11:34 ]
tabby
ベテラン
会議室デビュー日: 2002/06/26
投稿数: 55
お住まい・勤務地: 埼玉県・東京都
投稿日時: 2003-11-14 11:31
参照型の変数である p の型が ClassParent になっています。
この場合、 p を経由しては ClassParent に定義されている
メソッド・メンバ変数にしかアクセスできません。

インスタンスの型にあわせてキャストすると実行できます。
((ClassChild)p).getMsgChild();

オーバーライドすることで呼び出せるようになるのは ClassParent の
メソッドと同じ物?になるからです。
型と実体についてじっくりと考えてみてください。


このあたり、分かりやすく説明できるかたがいらっしゃいましたらお願いします。
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-11-14 12:40
ども、ほむらです。
継承に限らず大抵の場合、
子は親を知っていても
親は子を知りません。
(リアルとは反対ですね。 系図も反対ですけど(笑)

例題のコードは
ClassChild は ClassParentを継承しているのでClassParentの持つ情報は知っているけど
ClassParentはClassChildの親であってもClassParentでは
親子関係を直接は認識できないわけです。
結果としてClassParentはClassChildをまったく別のとして認識するので
ClassChildにしかない関数はだめというわけです。

僕的な感覚ではClassParent p = c;の時点で
エラーなり警告が出ないことのほうが不思議です
#訂正
#この場合は、ClassChild側のもつ系図上にClassParentがあるから
#警告とかエラーは出なくても不思議は無かったですね

また、tabby氏の言うように
アップキャスト(親から子へキャスト)してあげれば出来ることは出来ますけど
ダウンキャスト(子から親へキャスト)すら危険とされる世の中ですから
あまり推奨は出来ないですね

#以上C++の知識からでした^^;;;;;

#訂正の追加と多少文言の修正

[ メッセージ編集済み 編集者: ほむら 編集日時 2003-11-14 13:23 ]
空条Q太郎
会議室デビュー日: 2003/11/06
投稿数: 19
投稿日時: 2003-11-14 13:13
http://www.atmarkit.co.jp/fjava/rensai2/javaent04/javaent04.htmlの
『クラス継承の理解を深める』
が参考になりますでしょうか。(例は変数になってますが)
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-11-14 13:44
ども、ほむらです。
------------------
あぅごめんなさい。
個人的には空条Q太郎氏の言う連載は5回以降はともかくとして
それ以前はあまりお勧めできないです。。。
(@ITさんや筆者の方には申し訳ないのですが^^;;;)

理由は
突き詰めなくてもいい本質まで突っ走っていってしまっている。
そんな感じがするからです。
極端な話、Cを勉強するはずがアセンブラから始めてそれでもまだたりなくてさらに
マシン語までやっているくらい突っ走っていると思っています。
本来はCのライブラリについての注意事項をすべきなのに。。。
(strcpy()のオーバーバッファランの可能性とか)

Sun認定資格Javaプログラマーを受けようと思っているくらいですから
基本文法は大丈夫だと思いますが
googleで"Javaの道"を探したときにでてくるリファレンスは
リファレンスとして知ってると良いかなという内容があります。
連載のように説明はあまりないですけど
忍者鳥取県
ベテラン
会議室デビュー日: 2003/08/28
投稿数: 61
お住まい・勤務地: リオネジャネイロの地下6000Km
投稿日時: 2003-11-14 15:35
ご回答いただきましたみなさま、どうもありがとうございました。
m(_ _)mペコリコ
感謝感激雨あられちゃんです(T▽T)オロロ(感涙)

みなさまの温かいご指導により、なんとか言わんとしていることを
理解することができました。

試験は来週の月曜日です。みなさまのご恩に報いるためにも
絶対!、、いや、必ず!、、いえ、なんとか、、
いえ、できれば・・・もしかして・・・ひょっとして・・・
受かりたいと思う勢いです。どうぞ応援宜しくお願いします。
行ってきます♪ イザ出陣!(・_・、)オチタラドナイショ・・

スキルアップ/キャリアアップ(JOB@IT)