No Verse, você pode criar uma classe que estende a definição de outra classe adicionando ou modificando os campos e métodos dessa outra classe. Isso geralmente é chamado de subclasse ou herança, porque uma classe herda as definições da outra.
Vejamos o dispositivo Criador de Classes como um exemplo de subclasse. Com o dispositivo Criador de Classes, você pode criar classes de personagens para personagens de jogadores, que permitem definir os atributos e inventários específicos de uma classe de personagem, como um personagem "tanque" ou que gera um DPS (dano por segundo) alto.
![]() |
![]() |
| Classe de personagem DPS criada com o dispositivo Criador de Classes | Classe de personagem tanque criada com o dispositivo Criador de Classes |
No Verse, você pode criar uma classe tank e uma classe dps assim:
tank := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
DamageReduction : int
dps := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
MovementMultiplier : float
~~~
Como alguns dos campos nas duas classes são iguais, você pode reduzir a duplicação com uma superclasse que contém as propriedades e comportamentos compartilhados das classes. Vamos chamar essa superclasse de `player_character` e tornar `tank` e `dps` subclasses de `player_character`:
~~~(verse)
player_character := class():
StartingShields : int
MaxShields : int
AllowOvershield : logic
dps := class(player_character):
MovementMultiplier : float
tank := class(player_character):
DamageReduction : int
~~~
Como as classes `tank` e `dps` são subclasses de `player_character`, elas herdam automaticamente os campos e métodos da classe `player_character`, então você só precisa especificar o que é diferente da superclasse nesta classe.
Por exemplo, a classe `dps` adiciona apenas o campo `Movement Multiplier`, e a classe `tank` apenas adiciona o campo `DamageReduction`. Essa configuração é útil para quando você alterar o comportamento compartilhado das duas classes posteriormente, porque só precisará alterá-lo na superclasse.

Com o Verse, você pode adicionar mais alterações para diferenciar as classes tank e dps adicionando métodos às subclasses.
Um efeito útil da criação de subclasses é que você pode usar o relacionamento entre uma superclasse e suas subclasses. Por causa da herança, uma instância de `tank` é um `player_character` especializado, e uma instância de `dps` é outro `player_character` especializado, o que é chamado de uma [relação "is-a"](verse-glossary#is-a-relationship). Como tanto `tank` quanto `dps` são subclasses da mesma superclasse e divergem de sua superclasse compartilhada, `tank` não tem um relacionamento com `dps`.
## Substituir especificador
Para criar instâncias de classes com [valores](verse-glossary#value) iniciais, uma prática comum é ter uma [função](verse-glossary#function) que gera as instâncias. Por exemplo:
~~~(verse)
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}
~~~
As funções `CreateTankPlayerCharacter()` e `CreateDPSPlayerCharacter()` criam as instâncias com os valores iniciais apropriados. Como alternativa, você pode substituir os campos da superclasse e atribuir valores iniciais, para não precisar fornecer tantos valores iniciais ao criar uma instância.
Por exemplo, a classe "tank" da seção anterior pode ficar assim com substituições nos campos:
~~~(verse)
tank := class(player_character):
StartingShields<override> : int = 100
MaxShields<override> : int = 200
AllowOvershield<override> : logic = true
DamageReduction : int = 50
CreateTankPlayerCharacter() : tank =
return tank{}
Você também pode substituir métodos na subclasse, o que significa que é possível usar o método de substituição em qualquer lugar em que o método de substituição possa ser usado. Isso significa:
- O método deve aceitar pelo menos algum argumento aceito pelo método substituído, portanto, o tipo de parâmetro deve ser um supertipo do tipo de parâmetro da função substituída.
- O método não deve retornar um valor que o método substituído não poderia ter, portanto, o tipo de retorno deve ser um subtipo do tipo de retorno do método substituído.
- O método não deve ter mais efeitos do que o método substituído, então o especificador de efeito deve ser um subtipo do especificador de efeito do método substituído.
Super
Semelhante a Self, você pode usar (super:) para acessar as implementações de superclasse de campos e métodos. Para poder usar (super:), o campo ou método deve ser implementado na definição da superclasse.
~~~(verse) pet := class(): Sound : string
Speak() : void = Log(Sound)
cat := class(pet):
Sound
Speak
## Expressões block em um corpo de subclasse
Quaisquer expressões `block` que estão em um [corpo](verse-glossary#body) de subclasse serão executadas após as expressões `block` especificadas no corpo da superclasse. Por exemplo, no código a seguir, quando a instância da classe `cat` chamada MrSnuffles é criada, `Speak()` é executado primeiro, depois `Purr()`.
~~~(verse)
pet := class():
Speak() : void =
...
block:
Speak()
cat := class(pet):
Purr() : void =
...
block:
Purr()
MrSnuffles := cat{}
Especificador abstract (abstrato)
Quando uma classe ou um método de classe tem o especificador abstract, você não pode criar uma instância da classe. Classes abstract devem ser usadas como uma superclasse com implementação parcial ou como uma interface comum. Isso é útil quando não faz sentido ter instâncias de uma superclasse, mas você não deseja duplicar propriedades e comportamentos em classes semelhantes.
No exemplo a seguir, como pet é um conceito abstrato, uma instância da classe pet não é específica o suficiente, mas um pet gato (cat) ou cachorro (dog) faz sentido e, portanto, essas subclasses não são marcadas como abstract.
~~~(verse)
pet := class
cat := class(pet): Speak() : void = ...
dog := class(pet): Speak() : void = ... ~~~

