![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Sather はオブジェクト指向言語なので、クラス定義は中心的な機能です。
Sather のクラスシステムは結構複雑で、通常のクラスの他に 部分クラス (partial class)、 抽象クラス (abstracted class)、コンテナ型クラス (parametrized class)、変更不能クラス (immutable class) があります。 今回は通常のクラス、部分クラスについて説明し、コンテナ型クラス、抽象クラス、変更不能クラスは 7, 8 章で説明します。
今流行の携帯電話を例にとります。携帯電話は電話であり、かつメーラーとしても機能しますので、 電話とメーラーの属性を継承することになります。 Sather は多重継承をサポートしているので、電話クラス、 メーラークラス、携帯電話クラスは次のように書くことができます。
01: class PHONE is -- 電話クラスです 02: 03: private attr phone_number:STR; -- 電話番号です。private はプライベート変数。 attr はインスタンス変数の意味です。 04: -- private をつけないとパブリック変数になります。 05: 06: create(pn:STR):SAME is -- create は特殊なメソッドで、インスタンスを作るときは必ずこれを使います。 07: return new.init(pn); -- まず new でメモリー領域を確保して、それに init メソッドを作用させます。 08: end; -- 返り値 SAME は create を呼んだクラスです。継承を考えると SAME を使うのが良いでしょう。 09: 10: private init(pn:STR):SAME is -- init は初期化の関数です。create の書き方は他にもありますが、継承を考えると return new.init 11: phone_number := pn; -- と書くのが良いでしょう。インスタンス変数 phone_number を初期化します。 12: return self; -- 自分自身 (self) を返します。 13: end; 14: 15: get_number:STR is -- 電話番号を取得するメソッドです。self.phone_number の self は省略できます。 16: return phone_number; 17: end; 18: 19: phone_call(to:SAME, msg:STR):STR is -- 電話をかけるメソッドです。他の電話とメッセージを引数に取ります。 20: return "From: " + phone_number + -- 簡単のため文字列を返すだけです。 21: "\nTo: " + to.phone_number + -- to.phone_number のようにインスタンスを特定することもできます。 22: "\nSubject: " + msg + "\n"; -- この関数でも SAME を使っています。可能な限り SAME を使うほうが良いでしょう。 23: end; 24: end; -- end of PHONEその他
phone1:PHONE:=PHONE::create("012-345-6789"); -- 省略していない書き方です。省略形を使ってコンパイラーに文句を言われたらこう書く必要があります。 phone2:PHONE:=#PHONE("023-444-5555"); -- 通常は '#PHONE' で代用できます。 phone3:PHONE:=#("023-4545-6767"); -- さらに、作られるインスタンスの型が明らかな場合は '#' で代用できます。
01: class MAIL is 02: private attr address:STR; -- メールアドレス 03: private attr newmails:LIST{STR}; -- 新着メールリスト LIST{STR} 型 04: private shared mailinglist:LIST{STR}:=LIST{STR}::create; -- クラス属性 メーリングリスト (LIST{STR}) を宣言して作成。 05: -- constant と shared の場合は '#' を使った省略形が使えない。 06: create(ad:STR):SAME is 07: return new.init(ad); 08: end; 09: 10: init(ad:STR):SAME is 11: newmails := #LIST{STR}; -- 新着メールリストを作成。 12: address := ad; -- 自分のアドレスを設定 13: return self; -- 自分自身を返す 14: end; 15: 16: get_address:STR is -- アドレスを取得 17: return address; 18: end; 19: 20: send(to:SAME, msg:STR) is -- メールを送るメソッド。相手先の新着メールリストにメッセージを追加 21: to.newmails.append("From: " + address + "\nSubject: " + msg + "\n"); 22: end; 23: 24: send2mailinglist(msg:STR) is -- メーリングリストに投稿。メーリングリストにメッセージを追加 25: mailinglist.append("From: " + address + "\nSubject: " + msg + "\n"); 26: end; 27: 28: read_mail:STR is -- メールを読む。 29: s:STR := address + " received following new messages:\n"; 30: loop 31: s := s+ newmails.elt!; -- 新着メールリストから新着メールを取り出す 32: end; 33: newmails.clear; -- 新着メールをクリアする。 34: return s + "\n"; 35: end; 36: 37: read_mailinglist:STR is -- メーリングリストを読む。 38: s:STR := "Messages in the mailing list are:\n"; 39: loop 40: s := s+ mailinglist.elt!; 41: end; 42: return s + "\n"; 43: end; 44: 45: end; -- end of MAILメモ
01: class MOBILE is 02: include PHONE init -> phone_init, create ->; -- 継承は include で表します。 03: include MAIL init -> mail_init, create ->; -- 親クラスの init に別名をつけ、create は継承しません。 04: 05: create(ph,ad:STR):SAME is 06: return new.phone_init(ph).mail_init(ad); -- 親クラスの init 関数を使って簡潔に書けます。 07: end; 08: 09: end; -- end of MOBILE
01: class MAIN is 02: 03: main(av: ARRAY{STR}) is 04: if av.size = 5 then 05: mob1:MOBILE := #(av[1], av[2]); -- 携帯電話を 2 つ作って 06: mob2:MOBILE := #(av[3], av[4]); 07: mobile_test(mob1, mob2); -- 通話テストを行う。 08: else 09: #ERR + "Usage:mobile PHONE_NUMBER_1 EMAIL_ADDRESS_1 PHONE_NUMBER_2 EMAIL_ADDRES_2 \n"; 10: end; 11: end; 12: 13: mobile_test(mob1, mob2:MOBILE) is 14: #OUT + "Phone number(1) is " + mob1.get_number + "\n"; -- 携帯電話 (1) の電話番号を表示 15: #OUT + "E-mail address(1) is " + mob1.get_address + "\n"; -- 携帯電話 (1) のメールアドレスを表示 16: #OUT + "\nPhone call test (1) -> (2):\n" + -- 携帯電話 (1) から (2) に電話をかける。 17: mob1.phone_call(mob2, "Hello"); 18: #OUT + "\nE-mail transfer test (2) -> (1):\n"; 19: mob2.send(mob1, "How are you?"); -- 携帯電話 (2) から (1) にメールを送る。 20: mob2.send(mob1, "I want to see you."); -- 携帯電話 (2) から (1) にメールを送る。 21: #OUT + mob1.read_mail; -- 携帯電話 (1) が新着メールを見る。 22: #OUT + "\nTest for mailing list:\n"; 23: mob1.send2mailinglist("Is Sather good?"); -- 携帯電話 (1) がメーリングリストへメールを出す。 24: mob2.send2mailinglist("Yes. Sather is good."); -- 携帯電話 (2) がメーリングリストへメールを出す。 25: #OUT + mob1.read_mailinglist + "\n"; -- メーリングリストを見る。 26: end; 27: end; -- end of MAIN 28:
> sacomp mobile.sa -o mobile > ./mobile 012-222-3333 foo@ab.ne.jp 023-444-5677 bar@cd.com Phone number(1) is 012-222-3333 E-mail address(1) is foo@ab.ne.jp Phone call test (1) -> (2): From: 012-222-3333 To: 023-444-5677 Subject: Hello E-mail transfer test (2) -> (1): foo@ab.ne.jp received following new messages: From: bar@cd.com Subject: How are you? From: bar@cd.com Subject: I want to see you. Test for mailing list: Messages in the mailing list are: From: foo@ab.ne.jp Subject: Is Sather good? From: bar@cd.com Subject: Yes. Sather is good.
今流行の無線 LAN を例にとってみます。無線 LAN は盗聴される危険があるので、
個人レベルでも WEP か WPA-PSK などの暗号化を施す必要があります。
ここでは、部分クラス WLAN とそれを継承したクラス WEP, WPA_PSK を定義します。
01: -- an example of partical classes, WLAN 02: 03: partial class WLAN is 04: 05: stub security:STR; -- この属性は子クラスで再定義される必要がある。 06: 07: get_security:STR is 08: return security; -- security を取得するメソッド。 09: end; 10: 11: end; -- WLAN 12: 13: 14: class WEP is 15: include WLAN; 16: 17: const security:STR := "wep"; 18: private attr key:STR; 19: 20: create(k:STR):SAME is 21: return new.init(k); 22: end; 23: 24: init(k:STR):SAME is 25: key := k; 26: return self; 27: end; 28: 29: get_key:STR is 30: return key; 31: end; 32: 33: end; -- WEP 34: 35: class WPA_PSK is 36: include WLAN; 37: 38: const security:STR := "wpa psk"; 39: private attr key:STR; 40: 41: create(k:STR):SAME is 42: return new.init(k); 43: end; 44: 45: init(k:STR):SAME is 46: key := k; 47: return self; 48: end; 49: 50: get_key:STR is 51: return key; 52: end; 53: 54: end; -- WPA_PSK 55: 56: 57: 58: class MAIN is 59: 60: main is 61: wlan_test; 62: end; 63: 64: wlan_test is 65: wep0:WEP:=#("foo"); 66: wpa0:WPA_PSK:=#("bar"); 67: 68: #OUT + "Security and key of wep0 are: " + wep0.get_security + " and \"" + wep0.get_key + "\".\n"; 69: #OUT + "Security and key of wpa0 are: " + wpa0.get_security + " and \"" + wpa0.get_key + "\".\n"; 70: 71: end; 72: end; -- end of MAIN出力は以下のようになります。
$ sacomp wlan.sa -o wlan $ ./wlan Security and key of wep0 are: wep and "foo". Security and key of wpa0 are: wpa psk and "bar".
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |