Что я могу сделать с виртуальными классами?

Я видел (и слышал) довольно много шума о добавлении виртуальных классов в 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.

Помимо продемонстрированных свойств, переопределенные виртуальные классы также могут

  • ввести новые поля данных,
  • внедрить новые интерфейсы,
  • ввести новые наследственные отношения.
Другие вопросы по тегам