Edited at

HSPでモジュールの継承・ポリモーフィズム(多態性)っぽいもの

More than 1 year has passed since last update.

HSPでポリモーフィズムっぽい何かで他言語におけるポリモーフィズムみたいな書き方ができることを確認したので、例として15分でわかる かんたんオブジェクト指向の(J)から(N)位までのソースコードを移植・実装してみました。

純粋な継承はできないけど、継承されるモジュール側で十分にお膳立て(superメソッド・オーバーライドしたいモジュール関数の設定)をしっかりしてあげれば実用範囲で使用可能なのかな?

2018/2/18 追記: 継承先から継承元のモジュール変数にアクセスすることについて追記。


動作

HSP部屋


実装 (コメントまま)

#runtime "hsp3cl"


// getFullName以外をPersonに実装
#module Person givenName, familyName, age, getFullNamePtr

#modinit str initialGivenName, str initialFamilyName, int initialAge
super@Person thismod, initialGivenName, initialFamilyName, initialAge
getFullNamePtr = *getFullNameSub
return

#modfunc local super str initialGivenName, str initialFamilyName, int initialAge
givenName = initialGivenName
familyName = initialFamilyName
age = initialAge
return

*getFullNameSub
return "null" // 無意味な値を返す

#modcfunc getFullName
gosub getFullNamePtr
return refstr

#modcfunc getGivenName
return givenName

#modfunc setGivenName str newGivenName
givenName = newGivenName
return

#modcfunc getFamilyName
return familyName

#modfunc setFamilyName str newFamilyName
familyName = newFamilyName
return

#modcfunc getAge
return age

#modfunc setAge int newAge
age = newAge
return
#global

// Personを継承してWesternPersonを作る
// (extendsは継承を表すときに使われることが多いキーワード)
#module WesternPerson givenName, familyName, age, getFullNamePtr
// WesternPersonのコンストラクタ
#modinit str initialGivenName, str initialFamilyName, int initialAge
// 継承元のPersonのコンストラクタを呼んで初期化
// (superは継承元のクラスを表すときに使われることが多いキーワード)
super@Person thismod, initialGivenName, initialFamilyName, initialAge
getFullNamePtr = *getFullNameSub
return

// PersonではなくここでgetFullNameを実装
*getFullNameSub
// return getGivenName(thismod) + " " + getFamilyName(thismod) // 名 姓
return givenName@Person + " " + familyName@Person // 名 姓
#global

// Personを継承してEasternPersonを作る
#module EasternPerson givenName, familyName, age, getFullNamePtr
// EasternPersonのコンストラクタ
#modinit str initialGivenName, str initialFamilyName, int initialAge
// 継承元のPersonのコンストラクタを呼んで初期化
super@Person thismod, initialGivenName, initialFamilyName, initialAge
getFullNamePtr = *getFullNameSub
return

// PersonではなくここでgetFullNameを実装
*getFullNameSub
//return getFamilyName(thismod) + " " + getGivenName(thismod) // 姓 名
return familyName@Person + " " + givenName@Person // 姓 名
#global

newmod _westernPerson, WesternPerson, "Albert", "Einstein", 26
newmod _easternPerson, EasternPerson, "信長", "織田", 47

mes getFullName(_westernPerson) // Albert Einstein
mes getFullName(_easternPerson) // 織田 信長

newmod people, WesternPerson, "Albert", "Einstein", 26
newmod people, EasternPerson, "信長", "織田", 47
newmod people, WesternPerson, "Isaac", "Newton", 43
newmod people, EasternPerson, "秀吉", "豊臣", 61
newmod people, WesternPerson, "Galileo", "Galilei", 46
newmod people, EasternPerson, "家康", "徳川", 73

// peopleの要素を一つずつpersonに代入して実行されるfor-eachループ
foreach people
mes getFullName(people(cnt))
loop

// Personクラス
newmod _person, Person, "Albert", "Einstein", 26

mes getFullName(_person) // null


余談

ラベルを関数ポインタと見立ててモジュール変数に登録をしています。

gosubするまでは良いのですが、ラベルの名前空間?が呼び出されるモジュールと異なる場合、ダイレクトにモジュール変数を触ることができないため注意が必要です。

⇒ 継承元の名前空間に変数名を合わせれば可能なようです。ソースコードに直接追記しました。

あとはHSP3Dishではやはりgosub周りで挙動がおかしくなる様子。