enumオブジェクト
<定義側>
public enum CObjectStatus
{
Inactive, Active, Dying, Immune //準備状態、アクティブ、死亡状態、無敵状態
}
<実装側>
CObjectStatus test = CObjectStatus.Active;
主に状態(ステータス)を表す時に便利。こんなものでも型をあわせなければならないことに注意。
入れ子になったクラス関係
<定義側>
public class Class1
{
int val;
string str = "Class1Field_";
public NodeClass node; //ここをpublicにすれば外部から操れるし、privateにすればブラックボックスに出来る
public Class1()
{
val = 1234;
node = new NodeClass(val,str); //フィールドで実装は出来ないのでコンストラクタで行う。nodeにNodeClassを実装すればpublicで外部からインスタンスにアクセス可能となる
}
public class NodeClass //これが入れ子になった内部クラス
{
string strVal;
public NodeClass(int val,string str)
{
strVal = str+"Construct : val="+val;
}
public void Method()
{
Console.WriteLine(strVal);
}
}
}
<実装側>
Class1 class1 = new Class1();
class1.node.Method();
<出力>
Class1Field_Construct : val=1234
入れ子を有効に利用すると機能を実装する構造を内部に隠蔽し外部からアクセスする部分だけ公開することが容易に出来る
自作クラスライブラリを製作する際、基本的な考え方になる(非常に基礎的な確認の為ここに載せている)
継承とoverrideの特徴
<定義側>
public abstract class Class1
{
private string retVal;
public string RetVal
{
get { return this.retVal; }
set { this.retVal=value;}
}
protected Class1()
{
RetVal = "Class1Construct:";
}
public virtual void update()
{
RetVal += "Class1Update";
}
public virtual void draw()
{
Console.WriteLine("Class1_Draw:{0}", RetVal);
}
}
public class Class2 : Class1
{
public Class2()
{
RetVal = "Class2Construct:";
}
public override void update()
{
base.update();
RetVal += " + Class2Update";
}
public override void draw()
{
Console.WriteLine("Class2_Draw:{0}", RetVal);
}
}
public class Class3 : Class2
{
public Class3()
{
RetVal = "Class3Construct:";
}
public override void update()
{
base.update();
RetVal += " + Class3Update";
}
public override void draw()
{
Console.WriteLine("Class3_Draw:{0}", RetVal);
}
public void Method()
{
RetVal += " + Class3Method";
}
}
<実装側>
Class1 SetClass = new Class3();
((Class1)SetClass).update();
((Class1)SetClass).draw();
//インスタンスはClass3で作成している
//型をClass1にキャストして関数実行してもオーバーライドされているのでClass3のupdate()が実行される
//基底クラスの関数は上書きされる訳ではなく残っているので関数内のbase.update()で基底クラスの関数が実行できる
((Class3)SetClass).Method();
SetClass.draw();
//Class3にキャストしてメソッドを呼んでいる
SetClass = new Class2();
SetClass.update();
SetClass.draw();
//こちらはClass2でインスタンスを作った場合
//もちろんClass3のMethod()は呼べない
<出力結果>
Class3_Draw:Class3Construct:Class1Update + Class2Update + Class3Update
Class3_Draw:Class3Construct:Class1Update + Class2Update + Class3Update + Class3Method
Class2_Draw:Class2Construct:Class1Update + Class2Update
この仕組みを理解するに、あまり深い継承関係を築くとデバッグも大変そうだというのが分かる
些細なバグが発生し究明が基底クラスの深いクラスになってくると全ての構造を理解しないと原因が分からなくなりそうである
深い継承関係を作る際は注意
static readonlyの利用
<定義側>
namespace shooterGame
{
/// <summary>
/// ゲームにおける定数値を格納したクラス
/// </summary>
public class GameCenter
{
public static readonly float PixelsPerSecond = 200; //自機のスピード
public static readonly float RespawnTime = 5.0f; //プレーヤー無敵時間
public static readonly int bulletMax = 20;
public static readonly int rateOfFire = 4;
public static readonly int ShipControlSideSafeArea = 50; //左右の移動制限ピクセル数
}
}
<実装側>
else if(status== ObjectStatus.Immune) //無敵の時間切れ処理
{
if (totalGameSeconds > deathTimeTotalSeconds + (GameCenter.RespawnTime * 2))
{
status = ObjectStatus.Active;
}
上記の例のように定義側で変数をstaticにすることによってクラス名から値を直接呼ぶことが可能となる
内部では変数として扱われるのでconstのように定数として扱われないが分割コンパイルはしやすい
抽象クラスの利用(abstract)
<定義側>
public abstract class Person //抽象クラスなのでインスタンスを直接作れない
{
public virtual string Method() //しかしメンバ関数の中身は作れる
{
return "Personメソッド";
}
}
public class Taro : Person //継承したのでこれでインスタンスを作成可。抽象クラス内のメンバ関数も利用できる
{
}
public class Sato : Person //関数を上書き出来る
{
public override string Method()
{
return "サトー";
}
}
<実装側>
List<Person> test = new List<Person>(); //ここでは「型」としてPersonを利用している。型としてなら抽象クラスでも利用できる点に注意
//Person person = new Person(); //抽象クラスのインスタンスは作成できない
Taro taro = new Taro(); //抽象クラスを継承しているのでインスタンスを作成できる
Sato sato = new Sato();
test.Add(taro);
test.Add(sato);
foreach (Person val in test)
Console.WriteLine(val.Method());
最終更新:2010年10月26日 01:31