こんにちは。明月です。
この投稿はC#のthisとbaseのキーワードに関する説明です。
以前の投稿でクラスのインスタンスを生成する方法に関して説明したことがあります。
link - [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)
クラスの構成は基本的にメンバー変数と関数があります。C#にはプロパティやデリゲート、イベントなどがありますが、全部関数の変形型なので、関数で思えば良いです。
ここで我々がクラスを継承する時に親クラスのメンバー変数、関数を参照する時もあるし、本クラスを参照する時があります。その時に再定義する場合、関数名が同じなので参照する区分が必要です。
また、関数の中で、メンバー変数名とパラメータ名が同じの場合は?
using System;
namespace Example
{
// Exampleクラス
class Example
{
// dataのメンバー変数
private int data = 10;
// Print関数でdataというパラメータがある。
public void Print(int data)
{
// コンソール出力 - dataの出力はstack領域で一番近いところにあるパラメータのdataを指す。
Console.WriteLine("data - " + data);
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// Exampleクラスのインスタンスを生成
Example ex = new Example();
// 関数呼び出す - パラメータで20を入れる。
ex.Print(20);
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例をみればExampleクラスのPrint関数にはパラメータ名をdataで受け取ってクラスのメンバー変数にはdataの変数名があります。
この場合に関数の中でdata変数を呼ばれると基本的にStack領域の内部のdataを参照します。つまり、パラメータのdataを参照します。
そうならStackで同じ名の変数名がある場合にメンバー変数のdataを使うことできないかな。
そのため、thisキーワードがあります。
インスタンス中でthisの意味は本クラスのインスタンスを指すことになります。つまり、this.dataということに使うとメンバー変数を指すことになります。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// dataのメンバー変数
private int data = 10;
// Print関数でdataというパラメータがある。
public void Print(int data)
{
// コンソール出力 - this.dataはメンバー変数のdataを指す。
Console.WriteLine("data - " + this.data);
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// Exampleクラスのインスタンスを生成
Example ex = new Example();
// 関数呼び出す - パラメータで20を入れる。
ex.Print(20);
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例をみれば、this.dataはメンバー変数を指しているので、結果が10になることを確認しました。
少し正確にインスタンスのポインタアドレスで確認しましょう。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// 本インスタンスをリターンする。
public Example GetInstance()
{
// インスタンスをリターン
return this;
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// Exampleクラスのインスタンスを生成
Example ex = new Example();
// exのGetInstance関数でインスタンスを受け取る。
Example ex1 = ex.GetInstance();
// 二つの変数のハッシュコード値を比較、同じなら同じインスタンスという意味。
Console.WriteLine(ex.GetHashCode());
Console.WriteLine(ex1.GetHashCode());
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例でex変数名になっているインスタンスでGetInstance関数を呼び出してthisでリターンします。
thisはexのインスタンスを指すことです。リターンを受け取ったex1のhashcodeをみればexと同じインスタンスって確認できます。
そうならthisは自分のインスタンスを指していますが、継承する場合に親クラスを参照する必要がある時があります。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// メンバー変数
private int data = 10;
// メンバー変数のdataを返却する関数
public virtual int GetData()
{
// thisはExampleクラスのメンバー変数
return this.data;
}
}
// Exampleを継承するSubExampleクラス
class SubExample : Example
{
// メンバー変数
private int data = 20;
// メンバー変数のdataを返却する関数
public override int GetData()
{
// this는 SubExample 클래스의 맴버 변수
return this.data;
}
// 関数呼び出す。
public void Print()
{
// コンソール出力。 thisを使っているのでSubExampleクラスのメンバー変数を返却する。
Console.WriteLine("data - " + this.GetData());
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// Exampleクラスのインスタンスを生成
SubExample ex = new SubExample();
// Print関数を呼び出す。
ex.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
SubExampleでGetData関数を再定義しました。しかし、仕様により親クラスのGetData関数を参照したい時があります。その場合はthisではなく、baseキーワードで参照することができます。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// メンバー変数
private int data = 10;
// メンバー変数のdataを返却する関数
public virtual int GetData()
{
// thisはExampleクラスのメンバー変数
return this.data;
}
}
// Exampleを継承するSubExampleクラス
class SubExample : Example
{
// メンバー変数
private int data = 20;
// メンバー変数のdataを返却する関数
public override int GetData()
{
// this는 SubExample 클래스의 맴버 변수
return this.data;
}
// 関数呼び出す。
public void Print()
{
// コンソール出力。baseを使ったので親クラスのGetData関数を呼び出してExampleクラスのメンバー変数を返却する。
Console.WriteLine("data - " + base.GetData());
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// Exampleクラスのインスタンスを生成
SubExample ex = new SubExample();
// Print関数を呼び出す。
ex.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の場合はPrint関数でbaseキーワードを使っているので親クラスのExampleクラスのGetData関数が呼び出しました。
ExampleクラスのGetData関数でthisを使っていますが、この場合はSubExampleではなく、Exampleクラスのメンバー変数を参照することになります。
(※baseはthisみたいにインスタンス変換ができない。つまり、return baseということはあり得ない。)
そしてbaseは親クラスのコンストラクタ呼び出すこともできます。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// コンストラクタ
public Example(int data)
{
// コンソール出力
Console.WriteLine("call Example constructor - " + data);
}
}
// Exampleを継承したSubExampleクラス
class SubExample : Example
{
// コンストラクタ(ただし、コンストラクタパラメータがない場合には省略が可能。)
public SubExample(int data) : base(10)
{
// コンソール出力
Console.WriteLine("call SubExample constructor - " + data);
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// インスタンス生成
SubExample ex = new SubExample(10);
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
本クラスのコンストラクタの隣でコロン(:)を入れてbaseを入れて親クラスのコンストラクタを呼び出すことができます。
ここでコンストラクタにパラメータがない場合は省略もできます。
using System;
namespace Example
{
// Exampleクラス
class Example
{
// コンストラクタ(パラメータがない)
public Example()
{
// コンソール出力
Console.WriteLine("call Example constructor");
}
}
// Exampleを継承したSubExampleクラス
class SubExample : Example
{
// コンストラクタ(パラメータがない)
public SubExample()
{
// コンソール出力
Console.WriteLine("call SubExample constructor");
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// インスタンス生成
SubExample ex = new SubExample(10);
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例はbaseを入れなくても親クラスのコンストラクタが呼び出しました。
ここまでC#のthisとbaseのキーワードに関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [C#] 24. ラムダ式(匿名関数)とAction、Func関数を使い方、そしてクロージャ(Closure)2019/07/16 00:36:19
- [C#] 23. デリゲート(delegate)2019/07/15 02:25:26
- [C#] 22. インデクサー(indexer)を使う方法2019/07/13 01:06:04
- [C#] 21. C#のプロパティ(Property)2019/07/13 00:56:20
- [C#] 20. オブジェクト指向プログラミング(OOP)の4つの原則(カプセル化、抽象化、継承化、多相化(ポリモーフィズム))2019/07/12 00:17:35
- [C#] 19. 列挙型(enum)を使う方法2019/07/11 23:13:25
- [C#] 18. 構造体(Struct)、そして値型を参照するタイプ(Reference of value type)と参照型を参照するタイプ(Reference of reference type)2019/07/10 23:57:25
- [C#] 17. thisとbaseのキーワード2019/07/10 23:43:56
- [C#] 16. 継承禁止のキーワードのsealed2019/07/10 00:19:18
- [C#] 15. インタフェース(interface)2019/07/10 00:06:17
- [C#] 14. 抽象クラス(abstract)と抽象メソッド(abstract)、そして仮想関数(virtual)2019/07/08 23:04:09
- [C#] 13. クラスの継承と再定義(override)する方法、overrideとnewの差異2019/07/08 22:55:00
- [C#] 12. Staticとアクセス修飾子、そしてカプセル化2019/07/07 23:12:30
- [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)2019/07/07 22:54:13
- [C#] 10. クラスを作成する方法(コンストラクタ、デストラクタ)2019/07/06 00:53:17
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07