質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

2回答

2341閲覧

(C#)派生クラス→基底クラス→派生クラスのようなキャストを行っても、派生クラスのプロパティ値が欠落しないのは何故か?

firstlast

総合スコア138

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2019/07/10 10:25

前提

"動物クラス" と "動物クラスを継承している人間クラス" があり、
"動物クラス" には、名前プロパティと年齢プロパティが定義され、
"人間クラス" には、国籍プロパティが定義されています。

現象

まず、以下の手順で処理を行ないます。
①人間クラスのインスタンスを作り、名前、年齢、国籍を代入する。
②この人間クラスのインスタンスを動物クラスのインスタンスにキャストする。(ダウンキャスト)
③さらに、この動物クラスのインスタンスを人間クラスのインスタンスにキャストする。(アップキャスト)
※詳しくは、下記ソースコードをご参照ください。

すると、人間クラスのインスタンスの国籍プロパティに①で代入した国籍が格納されます。

図示するとこんな感じです。
イメージ説明

聞きたい事

動物クラスのインスタンスにキャストしたときに国籍プロパティの値が欠落して、最終的に国籍プロパティが空になると思ったのですが、何故、値が格納されているのでしょうか?

よろしくお願いします。

ソースコード

using System; using System.Diagnostics; using System.Windows.Forms; namespace ダウンキャストテスト { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// <summary> /// Animalクラス /// </summary> private class Animal { /// <summary> /// 名前プロパティ /// </summary> public string Name { get; set; } /// <summary> /// 年齢プロパティ /// </summary> public int Age { get; set; } /// <summary> /// コンストラクタ /// </summary> public Animal(string name, int age) { this.Name = name; this.Age = age; } } /// <summary> /// Humanクラス /// </summary> private class Human : Animal { /// <summary> /// 国籍プロパティ /// </summary> public string Nationality { get; set; } /// <summary> /// コンストラクタ /// </summary> /// <param name="name"></param> /// <param name="age"></param> /// <param name="nationality"></param> public Human(string name, int age, string nationality) : base(name, age) { Nationality = nationality; } } private void Button1_Click(object sender, EventArgs e) { //Humanクラスのインスタンスを作成 Human h1 = new Human("Taro", 3, "Japan"); Debug.WriteLine(string.Format("---(1)--- Name:{0}, Age:{1}, Nationality:{2}", h1.Name, h1.Age, h1.Nationality)); //Human型の変数 h1 をAnimal型の変数 a1 にキャスト Animal a1 = new Animal("---", 0); a1 = h1 as Animal; Debug.WriteLine(string.Format("---(2)--- Name:{0}, Age:{1}", a1.Name, a1.Age)); //Animal型の変数aをHuman型の変数h2にキャスト Human h2 = new Human( "---", 0, "---"); h2 = a1 as Human; Debug.WriteLine(string.Format("---(3)--- Name:{0}, Age:{1}, Nationality:{2}", h2.Name, h2.Age, h2.Nationality)); } } }

実行結果

---(1)--- Name:Taro, Age:3, Nationality:Japan ---(2)--- Name:Taro, Age:3 ---(3)--- Name:Taro, Age:3, Nationality:Japan

環境

Microsoft Windows 10 Pro (Version 1809)
Microsoft Visual Studio Community 2017(Version 15.9.4)
Microsoft .NET Framework(Version 4.7.03190)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Q71

2019/07/10 12:43

> Animal a1 = new Animal("---", 0); > Human h2 = new Human( "---", 0, "---"); 関係ないけど、この2行は無駄。↓ Animal a1 = h1 as Animal; Human h2 = a1 as Human;
firstlast

2019/07/10 15:41

ご指摘ありがとうございます。
firstlast

2019/07/10 15:48

インスタンスを作って、使わずに捨ててる感じですね。 ありがとうございました。m(_ _)m
guest

回答2

0

そのようなキャストによってデータの変換は起こりません。
「ポリモーフィズム」を調べてください。

投稿2019/07/10 10:29

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/07/10 10:33

> a1 = h1 as Animal; この後に a1.GetType() で a1 の型を取得してみてください。Human から変わっていないはずです。
firstlast

2019/07/10 15:38

おっしゃる通り {Name = "Human" FullName = "ダウンキャストテスト.Form1+Human"} となっていました。 また、ポリモーフィズムについても調べました。 ポリモーフィズム・・・多態性、多相性 アドホック多相・・・引数の型の組み合わせごとに異なる処理を同じメソッド名で呼び出せるしくみ。 パラメータ多相・・・いろんな型を扱えるジェネリックがこれに相当 部分型多相・・・・ 同じ基本クラスから派生した複数のクラスが同じメソッド名で実行されるしくみ 難しい概念ですね
Zuishin

2019/07/10 15:47

動物クラスにキャストすることによって動物クラスに変換されるのではなく、もともと人間クラスが持っていた動物クラスとしての側面のみ使用できるようになったと考えてください。 見方が人間から動物に変わっただけで中身は同じです。
firstlast

2019/07/10 15:48

ありがとうございました。m(_ _)m
guest

0

ベストアンサー

キャストしてもインスタンスは同じです
メモリ上に確保された領域に対してキャストした型としてのメンバにアクセスするだけです
なので、質問の図でいうと真ん中の動物クラスの場合はnewしたときに確保されたメモリのままですので、国籍プロパティが見えないだけで確保されたメモリにはいます

C#

1h2 = a1 as Human;

上記コードの次の行にブレークポイントを貼って、VisualStudioのデバッグ中の小技 ~ソースを弄らず変数をログ確認~を参考にして「出力ウィンドウにメッセージを記録する」に以下の内容を記述してみてください

h1={*&h1} a1={*&a1} h2={*&h2}

実行するとVSの出力ウィンドウの「出力元:デバッグ」に結果が出力されます
内容は、各変数で実際にデータが確保されているアドレスです
全て一致することが分かります

投稿2019/07/10 13:16

len_souko

総合スコア1348

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

firstlast

2019/07/10 15:46

C#でインスタンスのアドレスを確認できることを初めて知りました。 同じインスタンスを異なる眼鏡で見ている感じですね。 納得です。 ありがとうございました。m(_ _)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問