25行でC#のオブジェクト指向がわかった気になる
この物語はいつもLinuxでC書いてるプログラマが急にC#の案件を振られ、勉強のためいろいろコードを書いていたら、なんとなくオブジェクト指向がわかった気になる過程を淡々と描くものです。間違ってるかもしれないので過度な期待はしないでください。
前提知識
端々にCとの比較が出てきますが、Cの入門書をちょっとでもかじっていれば問題ないと思います。
注意!!
これはあくまでも自分がオブジェクト指向という考え方を勉強し、納得する過程をなぞったものであり、厳密な定義とは異なる解釈をしている場合があります。
まずは簡単な文法を確認
オブジェクト指向言語触るの初めて(´・ω・`)
クラス
class クラス名 {
static void Main() {
// 処理とかいろいろ
}
}
ふむふむ。なんとなくJavaとかC++でclassなんとかって書いてあるの見た気がする。
名前空間
namespace HelloWorld {
class Program {
// 処理とかいろいろ
}
}
namespace
?まあ、キーワード名からして#ifndef __MYLIB_H__
って書かなくても変数名とか関数名が衝突しないようにするためのものかな。
hello worldでも書いてみるか
using System;
namespace HelloWorld {
class Program {
static void Main() {
Console.WriteLine("Hello World");
}
}
}
コンパイルして実行。別にVisual Studioからでもいいけど、Vim大好きだから。Vim大好きだから!
C:\CSharp> csc hello1.cs
Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
Copyright (C) Microsoft Corporation. All rights reserved.
C:\CSharp> hello1.exe
Hello World
C:\>
おーけーおーけー
変数作ってみる
using System;
namespace HelloWorld {
class Program {
static void Main() {
int i;
int[] a = new int[5];
for (i = 0; i < a.Length; i++) {
a[i] = i * 100;
Console.WriteLine("a[{0}] = {1}", i, a[i]);
}
}
}
}
変数作って、配列作って、for
でa[]
の全要素にアクセスしてる。a.Length
はオブジェクト指向っぽい書き方だな。
ん?
int i;
はCと同じ書き方なのにnew int[5]
ってなんだ?
int i
とnew int[5]
の違い
Microsoftのドキュメントを開く。→ 共通型システム
C#の型は値型と参照型に大きく分けられる、と。
参照型?難しそうな言葉出てきた Oo(´・ω・`)
要は、値型は数字の型とstruct
で定義されたもので、参照型はclass
で定義されたもの、と。struct
で定義される構造体はCでも勝手にメモリーが割り当てられる。class
は自分でメモリーをnew
で割り当てる必要がある。malloc()
のC#版がnew
か。しかもガーベッジコレクションが勝手に不要になったメモリー回収するからfree()
不要。(Cも構造体の中にポインターがあってmallocするとかは一旦忘れて)
つまりあれか、参照型はCのポインターみたいなもんか!
色んな人に怒られそうなザックリ理解(´∀`;)
注意!!
厳密には違います。int
型はSystem.Int32
のエイリアス(別名)でしかなく、string
もSystem.String
のエイリアスです。C#では源泉を辿っていくとすべてのクラスはSystem.Object
の派生になっています。正確には値型はSystem.ValueType
を継承するクラス、参照型はそれ以外にSystem.Object
クラスから脈々と派生してできたクラス。
クラスを作ってみる
using System;
namespace HelloWorld {
class SuperText {
public string AddWorld(string s) {
return s + " World";
}
}
class Program {
static void Main() {
string s;
SuperText t = new SuperText();
s = Console.ReadLine();
s = t.AddWorld(s);
Console.WriteLine(s);
}
}
}
SuperText t = new SuperText();
はさっき調べたように、クラスだからnewでインスタンスを作る。Console.ReadLine()
はCのscanf()
みたいなやつ。Console.WriteLine()
はprintf()
みたいなやつ。
s = t.AddWorld();
はSuperText
クラスのAddWorld()
を呼び出してるんだな?見に行くぞ。
public string AddWorld(string s) {
は文字列型の引数を取って、外部からアクセスできるようにpublic
になってる関数(C#ではメソッドと言う)だな。private
と書くと他のクラスから使えなくなる。Cではファイル単位でやっていたアクセス制限をC#ではクラスと言う単位でやってる。
あれ?
オブジェクト指向って確か、データとそれを操作するメソッドを合わせたものじゃなかったっけ?string s
がボッチになっとる。
オブジェクト指向になる
つまり、SuperText
クラスにstring s
とAddWorld()
の両方を入れればいい。
using System;
namespace HelloWorld {
class SuperText {
private string str;
public void AddWorld(string s) {
str = s + " World";
}
public string GetResult() {
return str;
}
}
class Program {
static void Main() {
SuperText t = new SuperText();
t.AddWorld(Console.ReadLine());
Console.WriteLine(t.GetResult());
}
}
}
今度はSuperText
クラスの中にデータを保存するstring str
とそれを操作するAddWorld()
メソッドとGetResult()
メソッドがある。これで、文字列str
にはprivate修飾子がついているので、他のクラスが逆立ちしても直接str
の値を操作することができない。これがカプセル化(または隠蔽)というやつか。Cでもグローバル変数を使わず、きっちりとファイルスコープで変数とそれをイジれる関数を管理すればいいんだけどね。メンドイよね。クラスを使うとそれがサクッと出来ちゃう。
これがオブジェクト指向なのか。納得。(*゚∀゚)
C#には他にもインターフェイスやタプルやラムダ式やジェネリックやいろいろな概念が出てきます。一見して難解な概念でもそれはただ学習者を苦しめるためのものではなく、何かしらプログラミングを楽にするためもの。
言語の勉強で行き詰まってしまったら「この概念があるとどんないいことがあるのかな」と考えてみましょう。
で、どこが25行なのかというと、最後のソース
hello4.cs
です。