Verse では、他のクラスの フィールド や メソッド を追加または変更することで、別のクラスの 定義 を広げる クラス を作成できます。1 つのクラスが別のクラスから定義を継承するため、これは多くの場合、サブクラス化や 継承 と呼ばれます。
サブクラス化の例として、クラス デザイナー の仕掛けを見てみましょう。クラス デザイナーの仕掛けを使用すれば、タンクまたは DPS (1 秒あたりのダメージ) キャラクターなどのキャラクター クラス特有の属性やインベントリを定義できる、プレイヤー キャラクターのキャラクター クラスを作成することが可能です。
![]() |
![]() |
クラス デザイナーの仕掛けを使用して作成した DPS キャラクター クラス | クラス デザイナーの仕掛けを使用して作成したタンク キャラクター クラス |
Verse では、次のように tank
クラスと dps
クラスを作成できます。
tank := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
DamageReduction : int
dps := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
MovementMultiplier : float
2 つのクラスのフィールドの一部が同じであるため、クラスの共有のプロパティと動作を保持するスーパークラスで重複を減らすことができます。このスーパークラス player_character
を呼び出し、player_character
の tank
サブクラスおよび dps
サブクラスを作成します。
player_character := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
dps := class(player_character):
MovementMultiplier : float
tank := class(player_character):
DamageReduction : int
tank
クラスと dps
クラスは player_character
のサブクラスであり、player_character
クラスのフィールドとメソッドを自動的に継承するため、必要なのはこのクラスとスーパークラスの違いを指定することだけです。
たとえば、dps
クラスは Movement Multiplier
フィールドのみを追加し、tank
クラスは DamageReduction
フィールドのみを追加します。この設定は、後で 2 つのクラスの共有動作を変更するときに、スーパークラスで変更を行うだけで済むため便利です。

Verse では、サブクラスにメソッドを追加してさらに変更を加え、tank クラスと dps クラスを区別することができます。
サブクラス化の有用な効果は、スーパークラスとそのサブクラス間の関係を利用できる点にあります。継承により、tank
のインスタンスと dps
のインスタンスはそれぞれ、専用の player_character
と player_character
になりますが、これが is-a 関係 と呼ばれます。tank
と dps
はどちらも同じスーパークラスのサブクラスであり、共有のサブクラスから分かれるため、tank
と dps
の間に関係はありません。
override 指定子
初期 値 のあるクラスのインスタンスを作成する場合、インスタンスを生成する 関数 を作成するのが一般的な方法です。次に例を示します。
CreateDPSPlayerCharacter() : dps =
return dps{StartingShields := 0, MaxShields := 0, AllowOvershield := false, MovementMultiplier := 1.9}
CreateTankPlayerCharacter() : tank =
return tank{StartingShields := 100, MaxShields := 200, AllowOvershield := true, DamageReduction := 50}
CreateTankPlayerCharacter()
関数と CreateDPSPlayerCharacter()
関数は適切な初期値を含むインスタンスを作成します。または、スーパークラスからフィールドをオーバーライドして初期値を代入できるため、インスタンスを作成するときに多くの初期値を設定する必要はありません。
たとえば、前のセクションの tank クラスは、フィールドをオーバーライドすると次のようになります。
tank := class(player_character):
StartingShields<override> : int = 100
MaxShields<override> : int = 200
AllowOvershield<override> : logic = true
DamageReduction : int = 50
CreateTankPlayerCharacter() : tank =
return tank{}

また、サブクラスのメソッドをオーバーライドすることもできます。これは、オーバーライドされたメソッドを使用できるところではどこでもオーバーライドするメソッドを使用できることを意味します。 つまり、
- そのメソッドは、少なくともオーバーライドされたメソッドが受け付ける引数を受け入れる必要があります。そのため、パラメータの型はオーバーライドされた関数のパラメータの型のスーパータイプである必要があります。
- そのメソッドは、オーバーライドされたメソッドが取ることができない値を返さないようにする必要があります。そのため、戻り値の型はオーバーライドされたメソッドの戻り値の型のサブタイプである必要があります。
- そのメソッドは、オーバーライドされたメソッドより多くのエフェクトを含まないようにする必要があるため、エフェクト指定子 はオーバーライドされたメソッドのエフェクト指定子のサブタイプである必要があります。
Super
Self と同じように、(super:)
を使用してスーパークラスのフィールドやメソッドの実装にアクセスできます。(super:)
を使用できるようにするには、スーパークラスの定義でフィールドかメソッドを実装する必要があります。
pet := class():
Sound : string
Speak() : void =
Log(Sound)
cat := class(pet):
Sound<override> : string = "Meow"
Speak<override>() : void =
(super:)Speak() # アウトプット ログに「Meow」と表示される
Log("Purr") # アウトプット ログに「Purr」と表示される
サブクラス本体の block 式
サブクラス 本体 に含まれる block
式はすべて、スーパークラス本体で指定された block
式の後に実行されます。たとえば、次のコードで MrSnuffles という名前の cat
クラスのインスタンスを作成した場合、Speak()
の後に Purr()
が実行されます。
pet := class():
Speak() : void =
...
block:
Speak()
cat := class(pet):
Purr() : void =
...
block:
Purr()
MrSnuffles := cat{}
abstract 指定子
クラスまたはクラス メソッドに abstract
指定子 が含まれている場合、そのクラスの インスタンス を作成することはできません。抽象クラスは、部分的な実装を含むスーパークラス、または共通の インターフェース として使用されます。これは、スーパークラスのインスタンスを持つ意味がないものの、同じようなクラスでプロパティや動作を重複させたくない場合に便利です。
次の例では、ペット (pet) は抽象概念であるため、pet クラスのインスタンスは具体的ではありませんが、pet のネコ (cat) やイヌ (dog) は意味をなすため、こうしたサブクラスは abstract とマークされません。
pet := class<abstract>():
Speak() : void
cat := class(pet):
Speak() : void =
...
dog := class(pet):
Speak() : void =
...