[C#] 17. thisとbaseのキーワード


Study / C#    作成日付 : 2019/07/10 23:43:56   修正日付 : 2021/08/27 14:37:25

こんにちは。明月です。


この投稿は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#
最新投稿