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

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

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

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1068閲覧

インスタンスした継承先の子クラスを抽象クラス型の変数に入れた状態でメンバ変数にアクセスすると抽象クラスの初期値を参照してしまいます

ko_yu

総合スコア18

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

1グッド

0クリップ

投稿2022/06/11 19:37

編集2022/06/12 10:44

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Test : MonoBehaviour 6{ 7 public StateDataClass currentState; 8 public AttackState attackState; 9 10 private void Start() 11 { 12 attackState = new AttackState(); 13 currentState = attackState; 14 currentState.Method(this); 15 } 16} 17 18public abstract class StateDataClass 19{ 20 public string hoge = "抽象ステート"; 21 public bool piyo = false; 22 public virtual void Method(Test test) { } 23} 24 25public class AttackState : StateDataClass 26{ 27 public string hoge = "攻撃ステート"; 28 public bool piyo = true; 29 30 public override void Method(Test test) 31 { 32 Debug.Log("hoge:" + hoge + "  piyo:" + piyo); 33 Debug.Log("test.attackState.hoge:" + test.attackState.hoge+ "  test.attackState.piyo:" + test.attackState.piyo); 34 Debug.Log("test.currentState.hoge:" + test.currentState.hoge + " test.currentState.piyo:" + test.currentState.piyo); 35 } 36} 37 38

キャラクターのステートをクラスで管理するために、まず抽象クラスを作り、overrideしたメソッドと変数を持たせた継承先の子クラスAttackStateをTestキャラクター内でインスタンスしました。
TestキャラクターはcurrentStateという抽象クラス型の変数を持ち、この中にインスタンスした待機、攻撃、移動、といった子クラスを入れて状態遷移を行います。
しかしcurrentState経由でインスタンスした子クラスの変数にアクセスしたところ以下のように抽象クラスの変数が返ってきてしまいうまくいきません。

イメージ説明

currentState経由で継承先の子クラスのメンバ変数にアクセスするにはどのようにすればよいでしょうか?

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
(追記)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Test : MonoBehaviour 6{ 7 public StateDataClass currentState; 8 public AttackState attackState; 9 10 private void Start() 11 { 12 attackState = new AttackState(); 13 attackState.Huga = 50; 14 15 16 currentState = attackState; 17 currentState.Method(this); 18 19 if (currentState.piyo) { Debug.Log("現在のステートのpiyoがtrueの場合に処理する。piyoはステートによってtrueかflaseか差異がある(待機アニメはループ=trueだがジャンプアニメはfalse、など"); } 20 21 } 22 23 24 25 26} 27 28public abstract class StateDataClass 29{ 30 public string hoge = "抽象ステート"; 31 public bool piyo = false; 32 33 public int Huga { get; set; } = 100; 34 35 public virtual void Method(Test test) { } 36} 37 38public class AttackState : StateDataClass 39{ 40 41 public string hoge = "攻撃ステート"; 42 public bool piyo = true; 43 public int Huga { get; set; } = 50; 44 45 46 public override void Method(Test test) 47 { 48 49 50 Debug.Log("hoge:" + hoge + "  piyo:" + piyo); 51 Debug.Log("test.attackState.hoge:" + test.attackState.hoge+ "  test.attackState.piyo:" + test.attackState.piyo); 52 Debug.Log("test.currentState.hoge:" + test.currentState.hoge + " test.currentState.piyo:" + test.currentState.piyo); 53 54 Debug.Log("huga:" + Huga); 55 Debug.Log("test.currentState.Huga:" + test.currentState.Huga); 56 57 } 58} 59

イメージ説明

プロパティを試してみたのですが、上手く行きませんでした。
currentStateの中にあるAttackStateのhogeにアクセスしたいのですが、currentState自身のhogeにアクセスしているように見えます。
実装の仕方が間違っているでしょうか?
実装したい運用としては、
・TestキャラクタのステートであるcurrentStateは常に変化する
・各継承先ステートのメンバ変数は各ステート毎に差異がある(待機ならアニメループ判定はtrueだが、ジャンプはfalse)
・currentState.Method()とするとcurrentStateに代入されている継承クラスのメソッドにアクセスできるように、currentStateの中にある継承先クラスのメンバにアクセスしたい

となります。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
(追記)
TN8001さんの回答を元に記述したところ期待する結果が実装できました

C#

1public class Test : MonoBehaviour 2{ 3 public StateDataClass currentState; 4 public AttackState attackState; 5 6 private void Start() 7 { 8 attackState = new AttackState(); 9 10 11 currentState = attackState; 12 currentState.Method(this); 13 14 if (currentState.piyo) { Debug.Log("現在のステートのpiyoがtrueの場合に処理する。piyoはステートによってtrueかflaseか差異がある(待機アニメはループ=trueだがジャンプアニメはfalse、など"); } 15 16 } 17 18 19 20 21} 22 23public abstract class StateDataClass 24{ 25 public string hoge = "抽象ステート"; 26 public bool piyo = false; 27 28 public int Huga { get; set; } = 100; 29 30 public virtual void Method(Test test) { } 31} 32 33public class AttackState : StateDataClass 34{ 35 36 //public string hoge = "攻撃ステート"; 37 //public bool piyo = true; 38 //public int Huga { get; set; } = 50; 39 40 public AttackState() 41 { 42 hoge = "攻撃ステート"; 43 piyo = true; 44 } 45 46 47 public override void Method(Test test) 48 { 49 50 51 Debug.Log("hoge:" + hoge + "  piyo:" + piyo); 52 Debug.Log("test.attackState.hoge:" + test.attackState.hoge+ "  test.attackState.piyo:" + test.attackState.piyo); 53 Debug.Log("test.currentState.hoge:" + test.currentState.hoge + " test.currentState.piyo:" + test.currentState.piyo); 54 55 Debug.Log("huga:" + Huga); 56 Debug.Log("test.currentState.Huga:" + test.currentState.Huga); 57 58 } 59}

イメージ説明

TN8001👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

Visual Studioだとこういった警告が出るんですが、Unityのエディタでは出ないんですかね?

警告 CS0108 'AttackState.hoge' は継承されたメンバー 'StateDataClass.hoge' を非表示にします。非表示にする場合は、キーワード new を使用してください。

コンパイラの警告 (レベル 2) CS0108 | Microsoft Docs

やりたかったのはこういうことではありませんか?

cs

1public class AttackState : StateDataClass 2{ 3 //public string hoge = "攻撃ステート"; 4 //public bool piyo = true; 5 public AttackState() 6 { 7 hoge = "攻撃ステート"; 8 piyo = true; 9 } 10 // 以下省略 11}

この警告はAttackState.hogeが宣言されたことによって継承元である抽象クラスStateDataClassのhogeをAttasckStateクラス内においては上書きしました、という認識で使っていたのですがこれは間違っていますでしょうか?

元のhogebase.hogeとしてアクセスできます)は残ったまま、別のhogeAttackStateに作っています。
意図してやることもありますが、そういう場合は「明示的に隠ぺいしてますよ」ということでnewと付けます。
new 修飾子 - C# リファレンス | Microsoft Docs

↑の回答コードでは値そのものを上書きしました。

プロパティを試してみたのですが、上手く行きませんでした。

プロパティならメソッドと同じように、virtualabstractにできます。

cs

1namespace Qsg2zhvq2qgsipz 2{ 3 public abstract class StateDataClass 4 { 5 public string hoge1 = "抽象ステート"; 6 public string hoge2 = "抽象ステート"; 7 8 public string hoge3 { get; set; } = "抽象ステート"; 9 public string hoge4 { get; set; } = "抽象ステート"; 10 11 public virtual string hoge5 { get; set; } = "抽象ステート"; 12 public abstract string hoge6 { get; set; } 13 } 14 15 public class AttackState : StateDataClass 16 { 17 public string hoge1 = "攻撃ステート"; // CS0108 18 //public new string hoge1 = "攻撃ステート"; // CS0108が消える 意味は↑と同じ 19 20 public string hoge3 { get; set; } = "攻撃ステート"; // CS0108 21 //public new string hoge3 { get; set; } = "攻撃ステート"; // CS0108が消える 意味は↑と同じ 22 23 public override string hoge5 { get; set; } = "攻撃ステート"; 24 public override string hoge6 { get; set; } = "攻撃ステート"; 25 26 public AttackState() 27 { 28 hoge2 = "攻撃ステート"; 29 hoge4 = "攻撃ステート"; 30 //Console.WriteLine(base.hoge1); // 抽象ステート 31 //Console.WriteLine(base.hoge3); // 抽象ステート 32 //Console.WriteLine(base.hoge5); // 抽象ステート 33 //Console.WriteLine(base.hoge6); // エラー CS0205 抽象基本メンバーを呼び出すことはできません 34 } 35 } 36 37 class Program 38 { 39 static void Main() 40 { 41 AttackState attackState = new AttackState(); 42 StateDataClass currentState = attackState; 43 44 Console.WriteLine(attackState.hoge1); // 攻撃ステート 45 Console.WriteLine(currentState.hoge1); // 抽象ステート 46 47 Console.WriteLine(attackState.hoge2); // 攻撃ステート 48 Console.WriteLine(currentState.hoge2); // 攻撃ステート 49 50 Console.WriteLine(attackState.hoge3); // 攻撃ステート 51 Console.WriteLine(currentState.hoge3); // 抽象ステート 52 53 Console.WriteLine(attackState.hoge4); // 攻撃ステート 54 Console.WriteLine(currentState.hoge4); // 攻撃ステート 55 56 Console.WriteLine(attackState.hoge5); // 攻撃ステート 57 Console.WriteLine(currentState.hoge5); // 攻撃ステート 58 59 Console.WriteLine(attackState.hoge6); // 攻撃ステート 60 Console.WriteLine(currentState.hoge6); // 攻撃ステート 61 } 62 } 63}

投稿2022/06/12 08:23

編集2022/06/12 14:28
TN8001

総合スコア9432

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

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

ko_yu

2022/06/12 10:52

できました!ありがとうございます!でも原理がわからないので教えてください。 なぜAttackStateという継承先のクラス名と同じクラスを書き、そこにメンバ変数を代入すると期待した結果になるのでしょうか? また、私の環境でも警告が出ているのですが、この警告はAttackState.hogeが宣言されたことによって継承元である抽象クラスStateDataClassのhogeをAttasckStateクラス内においては上書きしました、という認識で使っていたのですがこれは間違っていますでしょうか? currentState.hogeはcurrentStateに代入されているAttckStateのhogeにアクセスする、という認識で使っていたのですが、 AttackStateクラス内にもう一度 AttackStateクラスを書くことでどうして差が出るのでしょうか?
TN8001

2022/06/12 11:40

> できました!ありがとうございます!でも原理がわからないので教えてください。 追記しました。 ちょっとややこしい(回りくどい?)コードのため混乱されているのかもしれませんが、もっと単純な話です。 CS0108が出ているということは、別のメンバーができてしまっているということです。
ko_yu

2022/06/12 12:53

ケースごとの例のコードありがとうございます! なるほど、継承先クラスのフィールドで同名変数を宣言する、もしくはoverrideしないプロパティは、上書きではなく継承先と抽象元にhogeが1つずつある状態になっていたということでしょうか。 コンストラクタを使う、overrideしたプロパティは抽象クラスの変数をきちんと引き継いで派生クラスにだけhogeを用意したということでしょうか。 そして同名変数宣言 or overrideしない場合は、currentState経由だとbase.hogeにアクセスしてしまう、ということなのだと理解しました。 詳しく教えてくださってありがとうございます! このCS0108は何度か見ていたのですが、いまいち理解できないままコードを打っていたので今日から認識を改めようと思います。
TN8001

2022/06/12 14:28

ちょっと例が足りず勘違いさせたかもしれません(更新しました) > 継承先クラスのフィールドで同名変数を宣言する、もしくはoverrideしないプロパティは、上書きではなく継承先と抽象元にhogeが1つずつある状態になっていたということでしょうか。 hoge1・hoge3のことですね。そうなります。 overrideは無関係です。hoge5も同様です。 > コンストラクタを使う、overrideしたプロパティは抽象クラスの変数をきちんと引き継いで派生クラスにだけhogeを用意したということでしょうか。 hoge2・hoge4に関しては、単にStateDataClassのメンバーを継承しているだけですので実体は1個です。 hoge5は上の通り2つということになります。 > そして同名変数宣言 or overrideしない場合は、currentState経由だとbase.hogeにアクセスしてしまう、ということなのだと理解しました。 hoge1・hoge3のような状態になるのは、あまりうれしくないので普通は使いません。 そうせざるを得ない時(親クラスに手を入れられない場合等)に、仕方がなくやる感じです。 やりたいことがあんまりわかっていないのですが、hoge2・hoge4で困らないのであればそれでいいと思います。 hoge2・hoge4でやりたいことができないのであれば、hoge5・hoge6ということになりますね(あるいはinterface)
ko_yu

2022/06/12 15:41 編集

捕捉ありがとうございます! なるほど、overrideではなくvirtualかabstarctの違いということですね。 ステート毎のアニメのループ判定用にbool変数を各ステートに持たせたかったので当面は2,4で対処できそうです。 詳しく解説してくれてすごく助かりました!
guest

0

変数はoverrideできないので、そういう場合はプロパティとしましょう

投稿2022/06/11 22:35

y_waiwai

総合スコア87804

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

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

ko_yu

2022/06/12 10:19

回答ありがとうございます。プロパティを使ってみたのですが、うまくいきませんでした。 継承先クラスのメンバ変数自体は変わっているようなのですが、currentState.Hugaと書くと、どうもcurrentStateを経由して中のメンバ変数にアクセスしているというより、currentState自体の変数を参照している気がします。 Testキャラクタのステートは常に変化してcurrentStateに格納される、継承先ステート毎に異なるメンバ変数にcurrentStateを経由してアクセスするにはどのようにすべきでしょうか?
y_waiwai

2022/06/12 11:24

プロパティにして、get、setに関数を割り当て、そいつをoverrideしましょう
ko_yu

2022/06/12 12:54

overrideしたプロパティでできました!ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.45%

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

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

質問する

関連した質問