ポリモーフィズム

ポリモーフィズムとは、異なる型を同一視することによって、複数のクラスを同じ操作で制御できる言語特性のことです。「オブジェクト指向」において、もっとも重要な機能の一つと言えるでしょう。

多くのデザインパターンは、このポリモーフィズムの機能を利用しています。

ポリモーフィズムを使わない例

using System;
using System.Collections.Generic;

namespace PolySample {
	class Program {
		static void Main(string[] args){
			List<object> list = new List<object>();
			list.Add(new CSharper());
			list.Add(new Rubyist());
			foreach(object p in list){
				if (p is CSharper){
					(p as CSharper).Work();
				} else if (p is Rubyist){
					(p as Rubyist).Work();
				}
			}
			Console.ReadLine();
		}
	}

	public class CSharper {
		public void Work() {
			Console.WriteLine ("C#でプログラムを書きます");
		}
	}

	public class Rubyist {
		public void Work () {
			Console.WriteLine ("Rubyでプログラムを書きます");
		}
	}
}

ポリモーフィズムを利用した例

using System;
using System.Collections.Generic;

namespace PolySample {
	class Program {
		static void Main(string[] args){
			List<Programmer> list = new List<Programmer> ();
			list.Add(new CSharper());
			list.Add(new Rubyist());
			foreach(Programmer p in list){
				p.Work ();
				}
			Console.ReadLine();
		}
	}

public abstract class Programmer {
	public abstract void Work ();
}

	public class CSharper : Programmer {
		public override void Work() {
			Console.WriteLine ("C#でプログラムを書きます");
		}
	}

	public class Rubyist : Programmer {
		public override void Work () {
			Console.WriteLine ("Rubyでプログラムを書きます");
		}
	}
}

静的メンバーと静的クラス

プログラムが開始されるときは、どのクラスのインスタンスもnewされていない状態です。

using System;

class Program {
	static void Main() {
		Console.Write ("ヤード ->");
		string s = Console.ReadLine ();
		double yard = double.Parse (s);
		double meter = YardToMeter (yard);
		Console.WriteLine ("{0}ヤードは{1}メートルです。", yard, meter);
		Console.ReadLine ();
	}

	// 静的メソッドとして定義
	static double YardToMeter (double yd)
	{
		double meter = yd * 0.9144;
		return meter;
	}
}

mono

C#のアクセス修飾子

クラスのメンバーへのアクセスを制御するためのものがアクセス修飾子です。C#には、「private」「public」「protected」「internal」の4つが用意されています。
publicなメンバーは、そのメンバーが定義されているクラスの外側から自由にアクセスすることが可能です。一方、privateなメンバーは、そのクラスの中からのみアクセスすることができます。

using System;
using System.IO;

namespace Sample {
	class Program {
		static void Main(string[] args){
			NumericsPicker np = new NumericsPicker ("Sample.txt");
			string line = np.GetNext ();
			while (line != null){
				Console.WriteLine (line);
				line = np.GetNext ();
			}
			Console.ReadLine ();
		}
	}

	class NumericsPicker {
		private StreamReader reader;
		public NumericsPicker(string filepath){
			reader = new StreamReader(filepath);
		}

		private bool IsAllDigits(string line){
			foreach (var c in line) {
				if (!char.IsDigit (c))
					return false;
			}
			return true;
		}

		public string GetNext(){
			string line = reader.ReadLine ();
			while (line != null && !IsAllDigits (line))
				line = reader.ReadLine ();
			return line;
		}
	}
}

メソッドのオーバーロード

クラスを使っていると、メソッド名が同じにもかかわらず、引数の数や引数の型が異なるメソッドがあります。これをメソッドのオーバーロードと言います。
例)

MessageBox.Show("hello world!");
MessageBox.Show("hello world!", "HelloDialog");

メソッドのオーバーロードは簡単です。また、引数の数が同じで、引数の型が異なるメソッドをオーバーロードすることもできます。
オーバーロード機能があることで、クラスを使う側も作る側も楽ができます。

using System;

namespace Sample {
	class Program {
		static void Main(string[] args){
			DateUtility du = new DateUtility ();
			// IsEndOfMonth(DateTime date)を呼び出す
			DateTime date = new DateTime(2011, 5, 30);
			bool eom1 = du.IsEndOfMonth (date);
			Console.WriteLine (eom1 == true ?
					"月末です" :
				"月末ではありません");
			// IsEndOfMonth(int year, int month, int day)を呼び出す
			bool eom2 = du.IsEndOfMonth(2011,2,28);
			Console.WriteLine (eom2 == true ?
				"月末です" :
				"月末ではありません");
			Console.ReadLine ();
		}
	}

	class DateUtility {
		public bool IsEndOfMonth(DateTime date){
			Console.WriteLine ("Call IsEndOfMonth(DateTime date)");
			return date.AddDays(1).Day == 1;
		}

		public bool IsEndOfMonth(int year, int month, int day){
			Console.WriteLine ("Call IsEndOfMonth(int year, int month, int day)");
			DateTime date = new DateTime (year, month, day);
			return IsEndOfMonth (date);

		}
	}
}

書籍を扱うクラス

規模が大きなプログラムを作るには、クラスの理解が必須。
とのことで、C#でのクラスを見てみましょう。

using System;

namespace ConsoleApplication1 {
	class Program {
		static void Main(string[] args){
			Book[] books = new Book[2];
			books[0] = new Book {
			title = "伊豆の踊り子",
			author = "川端康成",
			price = 380,
			publisher = "新潮社"
			};
			books [1] = new Book {
				title = "坊ちゃん",
				author = "夏目漱石",
				price = 378,
				publisher = "岩波書店"
			};
			foreach (Book book in books)
				Console.WriteLine ("{0} {1} {2} {3}",
					book.title, book.author,
					book.price, book.publisher);
			Console.ReadLine();
		}
	}

	class Book {
		public string title;
		public string author;
		public int price;
		public string publisher;
	}
}

簡易sleepコマンド

#include < time.h >
#include < stdio.h >
#include < stdlib.h >

int main(int argc, char **argv)
{
    struct timespec req;
    char *end;
    
    if(
        argc != 2 ||
       argv[1][0] == '\0' ||
       (req.tv_sec = strtol(argv[1], &end, 10), *end != '\0')
       ) {
        fprintf(stderr, "Usage: %s seconds \n", argv[0]);
        return 1;
    }
    
    req.tv_nsec = 0;
    
    if (nanosleep(&req, NULL) < 0){
        perror("naosleep");
        return 1;
    }
    return 0;
}

whoamiコマンド

getpwuid()を使います。

#include < unistd.h >
#include < sys/types.h >
#include < pwd.h >
#include < stdio.h >

int main(){
    pid_t euid;
    struct passwd *pw;

    euid = geteuid();

    if((pw = getpwuid(euid))== NULL){
        printf("%d\n", (int)euid);
    } else {
        printf("%s\n", pw->pw_name);
    }
    return 0;
}

簡易touchコマンド

#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#include < utime.h >
#include < stdio.h >

int main(int argc, char **argv)
{
    int i;
    int err = 0;
    
    if (argc <= 1){
        fprintf(stderr, "Usage: %s file...\n", argv[0]);
        return 1;
    }
    
    for (i = 1; i < argc; i++){
        open (argv[i], O_WRONLY|O_CREAT, 0666);
        
        if (utime(argv[i], NULL)){
            perror(argv[i]);
            err = 1;
        }
    }
    return err;
}

簡易rmコマンド

#include < unistd.h >
#include < stdio.h >

int main(int argc, char ** argv)
{
    int i;
    int err = 0;
    
    if (argc <= 1){
        fprintf(stderr, "Usage: %s file...\n", argv[0]);
        return 1;
    }
    
    for (i = 1; i < argc; i++){
        if (unlink(argv[i]) < 0){
            perror(argv[i]);
            err = 1;
        }
    }
    return err;
}

簡易mkdirコマンド

#include < sys/types.h >
#include < sys/stat.h >
#include < stdio.h >

int main(int argc, char **argv)
{
    int i;
    int err = 0;
    
    if (argc <= 1){
        fprintf(stderr, "Usage: %s file...\n", argv[0]);
        return 1;
    }
    
    for(i = 1; i < argc; i++){
        if(mkdir(argv[i], 0777)<0){
            perror(argv[i]);
            err = 1;
        }
    }
    return err;
}