クラスの基礎
ごくシンプルなクラス
まずはごくシンプルなクラスの定義してみます。
//SimpleClassという名前のクラスを定義
class SimpleClass
{
public void TestMethod()
{
Console.WriteLine("TestMethod実行");
}
}
static void Main(string[] args)
{
//SimpleClassのインスタンス生成
SimpleClass sc = new SimpleClass();
//SimpleClassのTestMethod実行
sc.TestMethod();
Console.ReadLine();
}
TestMethod実行
クラスはclass
というキーワードで作成します。
クラスの名称は自由です。
(変数名やメソッド名と同じ制限はあります)
定義したSimpleClass
クラスを実際に使うには、new
キーワードでSimpleClass型の変数を作成します。
この変数をインスタンスともいいます。
(オブジェクトとも言います。)
インスタンスとは「実体」という意味です。
クラスはデータの「設計図」で、内部にどのようなデータを持つかを決めるためのものです。
その設計図を元にして作られる「実体」がインスタンスというわけです。
設計図を元にして、実体であるインスタンスはいくらでも作ることができ、それぞれのインスタンスで独立した値を持つことができます。
変数sc
からはSimpleClass内で定義したメソッドを呼び出すことができます。
メソッドの呼び出しは変数名に続いて.
(ドット)を記述し、目的のメソッド名を記述します。
この使い方は今までにも何度か登場したもので、インスタンスを通して呼び出すメソッドなのでインスタンスメソッドといいます。
クラス内に定義される変数(フィールド)や関数(メソッド)などをメンバー(Member)と言います。
メソッド
クラスは内部にメソッド(Method)を持つことができます。
メソッドとは要するに関数のことです。
メソッドの定義方法は今までやってきた自作メソッドの定義と基本的に同じです。
ただし、今まで先頭に付けていたstatic
は記述しません。
その代わりというわけではありませんが、今回は先頭にpublic
というキーワードを付けます。
これの意味は後述します。
static
の意味はstatic
の項で説明します。
フィールド
クラスはメソッドだけではなく、変数も持つことができます。
クラス内の変数をC#ではフィールド(Field)といいます。
C++では、クラス内変数をメンバ変数といいます。
クラス内関数をメンバ関数といいます。
class SimpleClass
{
//フィールド
int fieldInt;
string fieldStr;
public void TestMethod()
{
//これはただのローカル変数
int num = 0;
Console.WriteLine("TestMethod実行");
Console.WriteLine(fieldInt);
Console.WriteLine(fieldStr);
}
}
static void Main(string[] args)
{
//SimpleClassのインスタンス生成
SimpleClass sc = new SimpleClass();
//SimpleClassのTestMethod実行
sc.TestMethod();
Console.ReadLine();
}
TestMethod実行 0
ローカル変数は初期化してからでないと使用できませんが、フィールドは初期化しない場合は自動的に既定値で初期化されます。
なので、上記コードのようにフィールドを初期化せずに使用してもエラーになりません。
フィールドの初期化
フィールドは宣言と同時に初期化することもできます。
class SimpleClass
{
int fieldInt = 10;
string fieldStr = "test";
}
インスタンス
クラスはデータの設計図で、定義しただけでは実際のデータ(実体)は持ちません。
設計図に基づいて作られる実際のデータがインスタンスです。
インスタンスはいくつでも作ることができ、それぞれで独立した値を内部に持つことができます。
class SimpleClass
{
public int FieldInt;
public string FieldStr;
}
static void Main(string[] args)
{
//インスタンスを生成
SimpleClass sc1 = new SimpleClass();
SimpleClass sc2 = new SimpleClass();
sc1.FieldInt = 10;
sc1.FieldStr = "aaa";
sc2.FieldInt = 20;
sc2.FieldStr = "bbb";
Console.WriteLine("{0}, {1}", sc1.FieldInt, sc1.FieldStr);
Console.WriteLine("{0}, {1}", sc2.FieldInt, sc2.FieldStr);
Console.ReadLine();
}
10, aaa 20, bbb
アクセス修飾子
メソッド名の先頭にはpublic
というキーワードを付けると説明しました。
これはアクセス修飾子というものです。
アクセス修飾子は、クラスの外部からのアクセスを許可するかしないか(アクセスレベル)を設定します。
アクセス修飾子には以下のものがあります。
- private
- 同じクラス内からのみアクセス可能。
- protected
- 同じクラスおよび継承クラスからのみアクセス可能。
- internal
-
同じアセンブリからのみアクセス可能
(同じプログラム内からのみ、と考えてOK) - public
- どこからでもアクセス可能
- protected internal
- protected + internalの領域
継承などはまだ説明していないので、今はprivate
とpublic
だけ覚えれば良いです。
internal
は他のプログラムと連携させる場合に、外部に公開したくないデータに付けます。
(今は気にする必要はありません)
例として、上記のSimpleClass
クラスのTestMethod
メソッドからpublic
を削除してみます。
class SimpleClass
{
void TestMethod()
{
Console.WriteLine("TestMethod実行");
}
}
static void Main(string[] args)
{
//SimpleClassのインスタンス生成
SimpleClass sc = new SimpleClass();
//「TestMethod」がないというエラーになる
sc.TestMethod();
}
SimpleClass
のインスタンスであるsc
からTestMethod
を呼び出そうとしても、そんなメソッドはないとエラーになってしまいます。
クラスのフィールドやメソッドはアクセス修飾子を付けない場合はprivate
が設定されます。
private
メソッドはそのクラスの外側からはアクセスできないので、Mainメソッドからは呼び出せなくなるのです。
private
メソッドは同じクラス内からであれば呼び出せますから、以下のコードはOKです。
class SimpleClass
{
public void TestMethodA()
{
Console.WriteLine("TestMethodA実行");
//同じクラス内のprivateメソッドを実行
TestMethodB();
}
private void TestMethodB()
{
Console.WriteLine("TestMethodB実行");
}
}
static void Main(string[] args)
{
SimpleClass sc = new SimpleClass();
sc.TestMethodA();
Console.ReadLine();
}
TestMethodA実行 TestMethodB実行
アクセス修飾子はメソッドのほか、フィールドやプロパティ、クラス自体にも付けることができます。
(プロパティについては未説明)
private class SimpleClass
{
//何も付けないとprivate
int num1;
//フィールド毎に指定できる
private int num2;
public string Str;
}
今まで自作メソッド名の前につけていたstatic
はアクセス修飾子ではありません。
これの意味はstatic
の項で説明します。
内部クラス
Visual StudioでC#プロジェクトを作成すると、以下のようなコードが自動的に生成されます。
(トップレベルステートメントを有効にしていない場合)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
}
}
}
これを見てわかる通り、自動的に「Program」という名称のクラスが作成され、その中にMainメソッドがあります。
今までの解説で作ってきた自作メソッドなども実際にはProgram
クラスのメソッドやフィールドを作っていたわけです。
ということは、このページの解説で作成したSimpleClass
クラスは、Program
クラス内に定義されたクラス(内部クラス)ということになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
class SimpleClass
{
public void TestMethod()
{
}
}
static void Main(string[] args)
{
}
}
}
クラスは内部にいくらでもクラスを定義することができます。
トップレベルステートメントを有効にしている場合、上記のようなクラスやMainメソッドは定義されませんが、コンパイル時に上記と同等のクラスとMainメソッドが自動的に生成されます。
トップレベルに記述したクラスも内部クラスになります。
クラスのアクセス修飾子
class
にもアクセス修飾子を付けることができます。
何も指定しないとprivate
になるのは同じです。
内部クラスを外部からも使用したい場合はpublic
を指定します。
内部クラスへのアクセスは「外部クラス名.内部クラス名」という形式で行います。
private class SimpleClass
{
//外部からアクセス不可
class InnerClassA
{
public void Func()
{
Console.WriteLine("InnerClassA");
}
}
//外部からアクセス可能
public class InnerClassB
{
public void Func()
{
Console.WriteLine("InnerClassB");
}
}
}
static void Main(string[] args)
{
//アクセス不可
//var innerA = new SimpleClass.InnerClassA();
var innerB = new SimpleClass.InnerClassB();
innerB.Func();
Console.ReadLine();
}
this
クラスのフィールドとメソッドを以下のように定義してみます。
private class SimpleClass
{
string firstName;
string lastName;
public void Test(string firstName, string lastName)
{
firstName = firstName;
lastName = lastName;
}
}
このコードのTest
メソッド内に記述されているfirstName
は「フィールド」なのでしょうか、それとも「引数」なのでしょうか。
この場合、firstName
は引数を意味します。
つまり上記のコードは引数を同じ引数に代入しているだけの意味のない処理となります。
(フィールドには何も代入されません)
フィールドと引数の名前が同じになると、そのメソッド内からはフィールドにアクセスできなくなります。
(最も内側のブロックで定義された名前が有効になります)
フィールド名か引数名かのどちらかの名前を変えれば良いのですが、引数やフィールドの名前というのはコードの読みやすさに関わってくるので、あまり変更したくない場合もあります。
名前の衝突を防ぐために、フィールド名の先頭にハイフン(_)を付ける、「m_」という接頭語を付ける、といったルールも決めてしまうのも一つの方法です。
(「m」というのは「メンバー」の意味)
その他、this
というキーワードを用いる方法もあります。
private class SimpleClass
{
string firstName;
string lastName;
public void Test(string firstName, string lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
}
このようにするとthis
が付いているものはフィールド(またはプロパティ)である、という意味になります。
正確にはthis
が指しているものは「自分自身」であり「自分」とは「インスタンス」のことです。
this
は呼び出し元のインスタンスへの参照です。
this.○○
は、そのメソッドを呼び出したインスタンスが内部に持っているデータにアクセスする、という意味になります。
private class SimpleClass
{
string str = "なし";
int num;
public void Test(string str)
{
//引数「str」にアクセス
Console.WriteLine(str);
//メソッドを呼び出したインスタンスが内部に持っている
//「str」にアクセス
Console.WriteLine(this.str);
//引数と名前が衝突していなくても
//thisキーワードは付けられる
this.num = 10;
}
}
static void Main(string[] args)
{
SimpleClass sc = new SimpleClass();
//インスタンスscは内部に
//str="なし", num=0
//というデータを持っている
//インスタンスからメソッドを呼び出す
sc.Test("aaa");
Console.ReadLine();
}
aaa なし