すこし、疑問におもい質問いたします。
以下のようなコードなのですが
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という子クラスにキャストしようとしていますが、どうも、親クラスから子クラスへキャストできないといいう例外が
発生するようです。
これはなぜなのでしょうか?
以上の点でご教授いただけませんでしょうか?
よろしくお願いします。
No.1ベストアンサー
- 回答日時:
まず,「オブジェクトの型」と,「変数の型」および「式の型」を区別して考えるようにして下さい。
キャストは,「式の型」を変更するものです。
# 「式の型」は,コンパイラが認識している型,とも言い換えられます。
・オブジェクトの型
オブジェクトを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 …
MSDN: ポリモーフィズム
http://msdn.microsoft.com/ja-jp/library/ms173152 …
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java final 1 2022/06/10 22:49
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- C言語・C++・C# 質問です 下記のコードを分かりやすく解説お願いします 初心者です #include ‹stdio.h 3 2022/05/26 22:03
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- PHP PHP一覧表示した項目にリンクをはりたい 1 2023/07/12 17:08
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- JavaScript [再掲]指定したパスが現URLに含まれていたら特定要素を削除するJavascriptのコードについて 1 2023/05/10 15:09
- その他(学校・勉強) Japanese schools tests 1 2022/08/19 14:41
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
interface,extend,implementの...
-
「ラッパークラス」の存在意義...
-
Javaのインスタンス化の構文の...
-
抽象クラスをJUNITでテストする...
-
「継承されたメソッドの可視性...
-
オブジェクト指向のインターフ...
-
System.Collections.Generic.Li...
-
C++ヘッダの肥大化
-
Strutsのバージョンアップによ...
-
ASP.NETでの共通コードの書き方...
-
VC#2008自作クラスメソッドツー...
-
JavaでのAPIの覚え方ってみさな...
-
c++でのヘッダーファイルの循環...
-
Javaで下線
-
全パッケージの取得、全クラス...
-
「インターフェイス」って何の...
-
VB DLLプロジェクトについて
-
ゲッターを使わないで変数にア...
-
JTextFieldの入力制限
-
C#からDLLを呼びたいのですが・...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
interface,extend,implementの...
-
(vba)他のアプリケーションの右...
-
抽象クラスをJUNITでテストする...
-
「ラッパークラス」の存在意義...
-
ASP.NETでの共通コードの書き方...
-
JTextFieldの入力制限
-
「継承されたメソッドの可視性...
-
VB DLLプロジェクトについて
-
C# 「データが失なわれる可能性...
-
c++でのヘッダーファイルの循環...
-
【C#】クラスのコンストラクタ...
-
「IOException は対応する try ...
-
メソッドの引数にクラス名を渡す
-
ファイルパスが取得出来ない(P...
-
ゲッターを使わないで変数にア...
-
Javaのインスタンス化の構文の...
-
オーバーライドとラッパーの違い
-
vb.net 自作プロパティの削除に...
-
なぜインタフェースを使うのか?
-
VBがオブジェクト指向言語でな...
おすすめ情報