p.167 コンストラクタ
・new等でインスタンスの生成を行う時に、同時に実行したい処理を特殊な書式で記述することができる
・これがコンストラクタで、省略すると、自動的に中身がないコンストラクタが用意されて用いられる
・コンストラクタ=構築なので、生成時に呼ばれる特殊なメソッドを指す
・コンストラクタを自前で記述することで、インスタンスの生成を行う時に実行したいことを書ける
・主に、データメンバの初期化や、開始処理などの記述に用いて「必ず実行させる」ことが可能
・なお、コンストラクタには名前はなく、クラス名で記述し、public指定で、戻り値はない
・主な書式: public クラス名() {…}
・「new クラス名()」で呼び出して欲しい場合はカッコ内は空にする
※ 引数を指定することも可能で、引数のない定義と両立できる(後述:オーバーロード)
p.167 construct01.cs
//p.167 construct01.cs
using System;
class MyClass {
int x; //外部から見えないインスタンス変数
public void showx() { //表示:インスタンスメソッド
Console.WriteLine("x = " + x);
}
public MyClass() { //コンストラクタ
x = 10; //インスタンス変数の初期化
Console.WriteLine("xに10を代入しました");
}
}
class construct01 {
public static void Main() {
MyClass mc = new MyClass(); //インスタンスの生成と共にコンストラクタを実行
mc.showx(); //インスタンスメソッドを実行
}
}
アレンジ演習:p.165 noreturnvalue.cs
・残高を0で初期化する処理をコンストラクタで行うようにしよう ・実行結果は変わらないので、テスト用にコンストラクタに「初期化しました」と表示する処理を加えよう
作成例
//アレンジ演習:p.165 noreturnvalue.cs
using System;
class Kakeibo {
private int total; //【変更】残高:外部から見えないインスタンス変数
public Kakeibo() { //【以下追加】コンストラクタ
total = 0; //インスタンス変数を初期化
Console.WriteLine("初期化しました"); //テスト用
}
public void nyukin(int en) { //入金:戻り値のないインスタンスメソッド
total += en;
Console.WriteLine("{0}円を入金しました", en);
// return; //この後はないので省略可能
}
public void shishutsu(int en) { //支出:戻り値のないインスタンスメソッド
if (total < en) { //残高不足?
Console.WriteLine("{0}円も支出できません", en);
// return; //この後にelseしかないので省略可能
} else {
total -= en;
Console.WriteLine("{0}円を支出しました", en);
// return; //この後はelseの終わりしかないので省略可能
}
}
public void gettotal() { //残高照会:戻り値のないインスタンスメソッド
if (total == 0) {
Console.WriteLine("残高はありません");
// return; //この後にelseしかないので省略可能
} else {
Console.WriteLine("残高は{0}円です", total);
// return; //この後はelseの終わりしかないので省略可能
}
}
}
class noreturnvalue {
public static void Main() {
Kakeibo k = new Kakeibo();
k.gettotal(); //残高照会⇒残高はありません
k.nyukin(1000); //入金1000円
k.gettotal(); //残高照会⇒1000円です
k.nyukin(2000); //入金2000円
k.gettotal(); //残高照会⇒3000円です
k.shishutsu(500); //支出500円
k.gettotal(); //残高照会⇒2500円です
k.shishutsu(10000); //支出10000円⇒支出できません
k.gettotal(); //残高照会⇒2500円です
}
}
p.168(引数のあるコンストラクタ)
・コンストラクタに引数リストを記述することができる
・これにより、インスタンス変数の初期値を引数で渡すことが多い
・例:
public Kakeibo(int t) { //引数のあるコンストラクタ
total = t; //インスタンス変数を引数の値で初期化
}
・引数のあるコンストラクタを呼び出すには、newのカッコ内に引数の値や式を記述する
・例:
Kakeibo k = new Kakeibo(10000); //インスタンスを生成し、残高を10000円とする
アレンジ演習:p.165 noreturnvalue.cs
・残高を引数tで初期化する処理をコンストラクタで行うようにしよう ・上記の例の通り、インスタンスを生成し、残高を10000円としよう
作成例
//アレンジ演習:p.165 noreturnvalue.cs
using System;
class Kakeibo {
private int total; //残高:外部から見えないインスタンス変数
public Kakeibo(int t) { //【変更】コンストラクタ
total = t; //【変更】インスタンス変数を引数で初期化
Console.WriteLine("初期化しました"); //テスト用
}
public void nyukin(int en) { //入金:戻り値のないインスタンスメソッド
total += en;
Console.WriteLine("{0}円を入金しました", en);
// return; //この後はないので省略可能
}
public void shishutsu(int en) { //支出:戻り値のないインスタンスメソッド
if (total < en) { //残高不足?
Console.WriteLine("{0}円も支出できません", en);
// return; //この後にelseしかないので省略可能
} else {
total -= en;
Console.WriteLine("{0}円を支出しました", en);
// return; //この後はelseの終わりしかないので省略可能
}
}
public void gettotal() { //残高照会:戻り値のないインスタンスメソッド
if (total == 0) {
Console.WriteLine("残高はありません");
// return; //この後にelseしかないので省略可能
} else {
Console.WriteLine("残高は{0}円です", total);
// return; //この後はelseの終わりしかないので省略可能
}
}
}
class noreturnvalue {
public static void Main() {
Kakeibo k = new Kakeibo(10000); //【変更】引数で残高の初期値を与える
k.gettotal(); //残高照会
k.nyukin(1000); //入金
k.gettotal(); //残高照会
k.nyukin(2000); //入金
k.gettotal(); //残高照会
k.shishutsu(500); //支出
k.gettotal(); //残高照会
k.shishutsu(10000); //支出
k.gettotal(); //残高照会
}
}
p.168(コンストラクタのオーバーロード)
・引数のないコンストラクタと、引数のあるコンストラクタを併記できる
・newにおいて引数が指定されたかどうかによって、自動的に使い分けが行われる
・また、この時に、引数とコンストラクタの引数リストのチェックが行われ、引数の個数と型が一致しないとエラーになる
・このチェックがあるので、引数のあるコンストラクタを複数併記でき、呼び出しを一致するものが利用される
・この仕掛けをオーバーロード(多重定義)という
・また、チェックに用いる「引数の個数と型の並び」をシグニチャという
・定義例:
public Kakeibo() { //引数の無いコンストラクタ
total = 0; //インスタンス変数を0で初期化
}
public Kakeibo(int t) { //int型引数1個のあるコンストラクタ①
total = t; //インスタンス変数を引数の値で初期化
}
public Kakeibo(int t, int u) { //int型引数2個のあるコンストラクタ②
total = t; //インスタンス変数を引数の値で初期化
count = u; //同上
}
・呼び出し例
Kakeibo n = new Kakeibo(); //インスタンスを生成し、引数の無いコンストラクタを呼ぶ
Kakeibo k = new Kakeibo(10000); //インスタンスを生成し、コンストラクタ①を呼ぶ
Kakeibo m = new Kakeibo(20000, 3); //インスタンスを生成し、コンストラクタ②を呼ぶ
・型の並びでも区別されるので、例えば、public Kakeibo(int t, double d)と、public Kakeibo(double d, int t)は併記可能
p.169 補足:construct02.csにおけるToString()について
・ToString()は一種のメソッドで、int.Parse()と同様に、intに対して指定でき、整数を文字列にした結果を返す ※ どちらも内部的には.NET型のSystem.Int32構造体(p.275)が持つオーバライドメソッド(p.230)
p.169 construct02.cs
//p.169 construct02.cs
using System;
class MyClass {
private string name; //名前:外部から見えないインスタンス変数
private int age; //年齢:外部から見えないインスタンス変数
private string address; //住所:外部から見えないインスタンス変数
public void Show() { //戻り値のないインスタンスメソッド
string toshi; //メソッド内で用いるローカル変数
if (age == -1) { //年齢が-1になっていたら
toshi = "不明";
} else {
toshi = age.ToString(); //int型から文字列化して代入
}
Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi);
}
public MyClass(string str) { //引数のあるコンストラクタ①(文字列:名前)
name = str;
address = "不定"; //住所は規定値
age = -1; //年齢は規定値
}
public MyClass(int x) { //引数のあるコンストラクタ②(整数:年齢)
age = x;
name = "不明"; //名前は規定値
address = "不定"; //住所は規定値
}
public MyClass(string str1, string str2, int x) { //引数のあるコンストラクタ③(文字列:名前,文字列:住所,整数:年齢)
name = str1;
address = str2;
age = x;
}
}
class construct01 {
public static void Main() {
MyClass mc1 = new MyClass(18); //コンストラクタ②が呼ばれる
MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①が呼ばれる
MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③が呼ばれる
mc1.Show();
mc2.Show();
mc3.Show();
}
}
アレンジ演習:p.169 construct02.cs
・名前と年齢を引数で受け取るコンストラクタ④を追加しよう ・Mainメソッドにおいて、コンストラクタ④を呼ぶ処理と、結果を表示する処理を追加しよう
提出:アレンジ演習:p.169 construct02.cs