Вложенные классы Delphi

Я делал сравнение между С++ и Delphi, и я нашел для меня что-то сложное.

Это очень простой код на С++:

template<typename T>
class C {

 class D {
  T x;
 }

}

В этом сценарии мы имеем, что класс C является классом шаблона (= общий класс), а вложенный класс D также является классом шаблона. Если T является double, x внутри D равно double.

Я не могу сказать этого:

template<typename T>
class C {

 template<typename T>
 class D {
  T x;
 }

}

Это ошибка, так как я уже "внутри" C, а другой T будет конфликтом. Чтобы исправить ошибку, я должен использовать другое имя, например U.

template<typename T>
class C {

 template<typename U>
 class D {
  T x;
 }

}

В Delphi я мог бы написать это:

type
 TClassC<T> = class
  private

   type
    TClassD = class
     private 
      x: T;
    end;

 end;

Если T является integer, теперь x является integer, поскольку (из того, что я понял, читающего онлайн) TClassD - integer. В Delphi это также законно:

type
 TClassC<T> = class
  private

   type
    TClassD<T> = class // <-- note the <T> repeated!!
     private 
      x: T;
    end;

 end;

Что теперь? Если я могу снова объявить T в TClassD, это означает, что без <T> у меня будет не общий класс TClassD. Правильно ли я?

Ответы

Ответ 1

Рассмотрим эту простую программу:

type
  TClassC<T> = class
  private
    type
    TClassD<T> = class
    private
      x: T;
    end;
  end;

var
  obj: TClassC<Integer>.TClassD<string>;

begin
  obj := TClassC<Integer>.TClassD<string>.Create;
  obj.x := 42;
end.

Эта программа компилирует, но испускает следующий намек:

[dcc32 Hint]: H2509 Идентификатор 'T' конфликтует с типом параметров типа контейнера

Назначение доказывает, что x берет его тип из внешнего общего параметра, а не из внутреннего.

Я должен сказать, что это меня удивило, потому что я ожидал обратного. Я ожидал, что внутренний общий параметр скроет внешний. Фактически, насколько я могу судить, для внутреннего типа нет способа ссылаться на его общий параметр.

Чтобы иметь возможность ссылаться на оба общих параметра, вам нужно будет использовать для них разные имена. Например:

type
  TClassC<T1> = class
  private
    type
    TClassD<T2> = class
    private
      x: T2;
    end;
  end;

Это то, что заставляет вас использовать аналогичный код шаблона С++.

На мой взгляд, это слабость дизайна языка Delphi, что вам разрешено компилировать код в верхней части этого ответа.