こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C#の継承関係。

すこし、疑問におもい質問いたします。

以下のようなコードなのですが
using System;
using System.Windows.Forms;

public class MainClass{

public static void Main (){
Test01 obj01 , obj02;
Test02 obj03 , obj04;

obj01= new Test01();
obj01.method01();

obj03 = new Test02();
obj03.method02();

try{
obj02 = (Test01)obj03;(1)

//obj02.methodp();(2)

obj04 = (Test02)obj01;(3)
}catch(Exception e){
MessageBox.Show(e.Message);
}
}
}

public class Test01{

public void method01(){
MessageBox.Show("スーパークラスメソッド");
}

private void methodp (){
MessageBox.Show("スーパークラスプライベートメソッド");
}
}

public class Test02 : Test01{

public void method02(){
MessageBox.Show("サブクラスメソッド");
}
}

まず(1)の箇所ですが、これはTest02というTest01のクラスを継承したサブクラスを
Test01という親クラスにキャストしてます。
これは、問題なく動いているようです。
ただ、その下の(2)の箇所でキャストしたインスタンスから親クラスのプライベートメソッドにアクセスしようとしたらコンパイル時にエラーとなりました。
サブクラスを親クラスにしても親クラスのプライベートメソッドって使えないのでしょうか?であれば親クラスへのキャストって何のためにあるのでしょうか?


次に(3)の箇所ですが、これはTest01という親クラスをTest02という子クラスにキャストしようとしていますが、どうも、親クラスから子クラスへキャストできないといいう例外が
発生するようです。
これはなぜなのでしょうか?

以上の点でご教授いただけませんでしょうか?
よろしくお願いします。

投稿日時 - 2011-11-06 16:01:11

QNo.7116940

すぐに回答ほしいです

質問者が選んだベストアンサー

まず,「オブジェクトの型」と,「変数の型」および「式の型」を区別して考えるようにして下さい。
キャストは,「式の型」を変更するものです。
# 「式の型」は,コンパイラが認識している型,とも言い換えられます。

・オブジェクトの型
オブジェクトをnewした時の型です。
newした時点で決定し,変更されることはありません。

・変数の型
変数を宣言した時に使用された型です。
変数を宣言した時点で決定し,変更されることはありません。

・式の型
式や部分式におけるオブジェクトの型です。
メソッドの呼び出しなど,コンパイラが知っている型であり,
 ・変数を使用した場合,その式は変数の型が式の型
 ・new式では,newしたオブジェクトの型が式の型
 ・メソッド呼び出しでは,メソッドの戻り値の型が式の型
 ・プロパティアクセスでは,プロパティの型が式の型
のようになっています。
式の型に定義されていないメソッド等は,たとえ派生クラスで定義されていても利用することはできません。


> Test01 obj01 , obj02;
> Test02 obj03 , obj04;

変数の宣言ですから,obj01等の変数の型が決定します。
つまり,obj01とobj02はTest01型,obj03とobj04はTest02型です。

> obj01= new Test01();
> obj03 = new Test02();

new Test01()でTest01型のオブジェクトが生成されます。
また,new Test01()という式は生成したオブジェクトへの参照が式の値となり,その式の型はTest01型になります。


> obj02 = (Test01)obj03;(1)

ここでは,Test02型の変数が指すオブジェクトをTest01型とみなしてTest01型の変数obj02に代入しようとしています。
この時,obj03の「変数の型」および「式の型」はTest02型,(Test01)obj03の「式の型」はTest01型です。
ここで,キャストはオブジェクトの型を変更しません。
つまり,obj02が指すオブジェクトはTest02型のままです。
# Test01型はTest02型の基本クラスであるため,キャストは不要です。


> //obj02.methodp();(2)
> ただ、その下の(2)の箇所でキャストしたインスタンスから親クラスのプライベートメソッドにアクセスしようとしたらコンパイル時にエラーとなりました。
> サブクラスを親クラスにしても親クラスのプライベートメソッドって使えないのでしょうか?であれば親クラスへのキャストって何のためにあるのでしょうか?

privateメソッドへアクセスできるのは,
・定義したクラス
・定義したクラスの中で定義されたクラス (recursive)
のみです。
今回の場合,MainClass内のMainメソッドから,Test01内のprivateメソッドを利用しようとしているためにエラーになっています。
これはキャストや派生関係とは無関係にエラーになります。
# obj01.methodp();でもエラーになります。


上記で書いた通り,privateメソッドは派生クラスからアクセスできません (Test02からmethodpを呼び出せない)。
外部からアクセスできず,派生クラスのみからアクセスできるように指示するには,protectedを使います。

基本クラスを式の型とするのは,
・if文等で複数の派生クラスから一つを選ぶ場合など (基本クラスで変数を宣言する)
・newを使って再定義している場合に基本クラス側のものにアクセスする
・インターフェイスの明示的な定義をされているメソッドを呼び出す
などを目的とする時です。
# Javaはできる限り基本クラスで,みたいな習慣がありますが,C#にはそのような習慣はありません。
2番目の項目は以下のような場合です。
public FooBase
{
public void Func1 () { System.Diagnostics.Debug.WriteLine("FooBase.Func1"); }
public virtual void Func2 () { System.Diagnostics.Debug.WriteLine("FooBase.Func2"); }
}
public FooDerived : FooBase
{
public void Func1 () { System.Diagnostics.Debug.WriteLine("FooDerived.Func1"); }
public virtual void Func2 () { System.Diagnostics.Debug.WriteLine("FooDerived.Func2"); }
}

FooDerived d = new FooDerived();
d.Func1(); // FooDerived.Func1
d.Func2(); // FooDerived.Func2
FooBase b = d;
b.Func1(); // FooBase.Func1
b.Func2(); // FooDerived.Func2


> obj04 = (Test02)obj01;(3)
> 次に(3)の箇所ですが、これはTest01という親クラスをTest02という子クラスにキャストしようとしていますが、どうも、親クラスから子クラスへキャストできないといいう例外が
> 発生するようです。

obj01が指すオブジェクトはTest01型です。
Test01型はTest02型を継承していないため,このオブジェクトをTest02型とみなすことはできません。
よって,ここでInvalidCastExceptionが発生します。

「オブジェクトの型」が継承しているクラスまたは実装しているインターフェイスに対してのみ,
キャストによって「式の型」を変更できます。
例えば,上記が
obj04 = (Test02)obj02;
であれば,obj02はTest02型のオブジェクトを指していますから,キャスト可能です。


references)
MSDN: キャストと型変換
http://msdn.microsoft.com/ja-jp/library/ms173105.aspx
MSDN: ポリモーフィズム
http://msdn.microsoft.com/ja-jp/library/ms173152.aspx

投稿日時 - 2011-11-06 19:29:01

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問