Что я могу сделать с виртуальными классами?
Я видел (и слышал) довольно много шума о добавлении виртуальных классов в Scala (у него уже есть виртуальные типы, по словам Мартина Одерского).
Каков непрофессионал (возможно, с примером) о том, что такое виртуальный тип и что могло бы быть возможно, если бы Scala имела виртуальные классы?
([У меня нет опыта работы с C или C++, поэтому я предпочел бы, чтобы любой ответ не относился к этим языкам].)
1 ответ
Виртуальные типы просты:
Классы и черты могут иметь членов типа. Например
trait Foo { type T }
Они могут быть уточнены (но не переопределены после определения):
class Foo1 extends Foo { type T <: AnyVal } class Foo2 extends Foo1 { override type T = Boolean } class Foo3 extends Foo2 { // override type T = Int // rejected by the compiler – would be unsound }
Вот пример виртуальных классов на языке Java-потомков (cclass
это виртуальный класс):
Особенности виртуальных классов
Давайте посмотрим на другой пример, чтобы изучить возможности виртуальных классов. Мы будем использовать виртуальные классы для расширения сотрудничества с совершенно новой функциональностью. Допустим, у нас есть базовая модель данных для представления выражений:
public cclass ExprModel { abstract public cclass Expr {} public cclass Constant extends Expr { protected int _val; public Constant(int val) { _val = val; } } abstract public cclass BinaryExpr { protected Expr _left; protected Expr _right; public BinaryExpr(Expr left, Expr right) { _left = left; _right = right; } } public cclass Add extends BinaryExpr {} public cclass Mult extends BinaryExpr {} }
Сотрудничество определяет Expr как базовый класс для всех выражений, конкретные классы для представления констант, сложения и умножения. Класс BinaryExpr реализует общую функциональность всех выражений с двумя операндами. Обратите внимание, что текущая версия Caesar не поддерживает конструкторы с параметрами и абстрактными методами в cclass. Приведенный ниже код демонстрирует, как примеры выражений могут быть построены с использованием такого сотрудничества:
public model.Expr buildSampleExpr(final ExprModel model) { model.Expr const1 = model.new Constant(-3); model.Expr const2 = model.new Constant(2); model.Expr op1 = model.new Mult(const1, const2); model.Expr const3 = model.new Constant(5); model.Expr op2 = model.new Add(op1, const3); return op2; }
Сотрудничество определяет Expr как базовый класс для всех выражений, конкретные классы для представления констант, сложения и умножения. Класс BinaryExpr реализует общую функциональность всех выражений с двумя операндами.
Существует множество различных функций, связанных с выражениями: их оценка, форматирование выражений в простой текст в инфиксном или постфиксном порядке, различные проверки целостности, поиск и преобразования. Мы хотим, чтобы вся эта конкретная функциональность была отделена друг от друга и от базовой модели данных. Это может быть достигнуто с помощью виртуальных классов. Например, приведенная ниже совместная работа расширяет базовую модель простыми функциями форматирования выражений:
public cclass ExprFormat extends ExprModel { abstract public cclass Expr { abstract public void String format(); } public cclass Constant { public void String format() { return _val < 0 ? “(“ + _val + “)” : “” + _val; } } abstract public cclass BinaryExpr { public void String format() { return “(” + _left.format() + getOperSymbol() + _right.format() + “)”; } abstract public void String getOperSymbol(); } public cclass Add { public void String getOperSymbol() { return “+”; } } public cclass Mult { public void String getOperSymbol() { return “*”; } } }
Этот короткий пример демонстрирует различные функции виртуальных классов:
Нет необходимости повторять отношения наследования между виртуальными классами, если они уже определены в суперколлаборации. Например, ExprModel определяет Constant как подкласс Expr. Это означает, что Constant неявно предполагается как подкласс Expr в ExprFormat.
Виртуальные классы могут использовать поля и методы, определенные в их старых версиях. Например, ExprFormat.BinaryExpr может использовать поля _left и _right, определенные в ExprModel.BinaryExpr.
Функциональность, определенная в переопределенных виртуальных классах, может быть доступна без приведения типов. Например, поля _left и _right BinaryExpr были первоначально объявлены с типом Expr ExprModel, который не имеет метода format(), но в контексте ExprFormat новая версия Expr предполагается как тип _left и _right. Поэтому format () может быть вызвана без приведения типов.
Методы, представленные в переопределенных виртуальных классах, могут быть снова переопределены в новых версиях подклассов. Например, переопределенный Expr представляет метод format(), который может быть переопределен в BinaryExpr. Хотя Add и Mult больше не переопределяют этот метод, они наследуют формат () BinaryExpr.
Помимо продемонстрированных свойств, переопределенные виртуальные классы также могут
- ввести новые поля данных,
- внедрить новые интерфейсы,
- ввести новые наследственные отношения.