Нужно ли помещать слова перегрузки или переопределения после объявления конструктора в производном классе? - PullRequest
7 голосов
/ 11 декабря 2008

У меня есть иерархия классов, эта:

type
TMatrix = class
    protected
      //...
    public
      constructor Create(Rows, Cols: Byte);
    //...
type
  TMinMatrix = class(TMatrix)
    private
      procedure Allocate;
      procedure DeAllocate;
    public
      constructor Create(Rows, Cols: Byte);
      constructor CreateCopy(var that: TMinMatrix);
      destructor Destroy;
  end;

Итак, как вы видите, и конструкторы производного, и базового классов имеют один и тот же список параметров. Я явно вызываю конструктор базового класса из производного:

constructor TMinMatrix.Create(Rows, Cols: Byte);
begin
   inherited;
   //...
end;

Необходимо ли явно вызывать конструктор базового класса в Delphi? Может быть, мне нужно поставить перегрузку или переопределить, чтобы очистить, что я собираюсь делать? Я знаю, как это сделать в C ++ - вам нужен явный вызов конструктора базового класса, только если вы хотите передать ему некоторые параметры, - но у меня нет большого опыта программирования на Delphi.

Ответы [ 4 ]

14 голосов
/ 11 декабря 2008

Насколько я знаю, здесь есть две отдельные проблемы:

Убедитесь, что конструктор дочернего класса вызывает конструктор базового класса

Вам придется явно вызвать конструктор базового класса:

constructor TMinMatrix.Create(Rows, Cols: Byte);
begin
   inherited;
   //...
end;

Убедиться, что конструктор дочернего класса переопределяет конструктор базового класса

Вы также также должны будете создать дочерний класс 'constructor override и базовый класс' constructor virtual, чтобы компилятор видел связь между ними. Если вы этого не сделаете, компилятор, вероятно, предупредит вас, что конструктор TMinMatrix «скрывает» конструктор TMatrix. Итак, правильный код будет:

type
TMatrix = class
    protected
      //...
    public
      constructor Create(Rows, Cols: Byte); virtual;    // <-- Added "virtual" here
      //...
type
  TMinMatrix = class(TMatrix)
    private
      //...
    public
      constructor Create(Rows, Cols: Byte); override;   // <-- Added "override" here
      constructor CreateCopy(var that: TMinMatrix);
      destructor Destroy; override;                     // <-- Also make the destructor "override"!
  end;

Обратите внимание, что вы также должны сделать свой деструктор override.

Представляем конструктор с разными параметрами

Обратите внимание, что вы можете переопределить конструктор только с тем же списком параметров. Если дочернему классу нужен конструктор с другими параметрами, и вы хотите предотвратить непосредственный вызов конструкторов базового класса, вы должны написать:

type
TMyMatrix = class(TMatrix)
//...
public
  constructor Create(Rows, Cols, InitialValue: Byte); reintroduce; virtual;
//...
end

implementation

constructor TMyMatrix.Create(Rows, Cols, InitialValue: Byte);
begin
  inherited Create(Rows, Cols);   // <-- Explicitly give parameters here
  //...
end;

Надеюсь, это прояснит ситуацию ... Удачи!

3 голосов
/ 12 декабря 2008

Вам необходимо явно вызвать унаследованный метод; Delphi не сделает это за вас. Это сделано специально, потому что есть случаи, когда вы работаете с виртуальными методами, например, когда вы не хотите вызывать унаследованное поведение.

Также, исходя из личных предпочтений, мне нравится полностью выписывать унаследованный вызов. ( унаследовано Create (Rows, Cols); в отличие от унаследованного; по одной простой причине: это значительно облегчает обход кода. вызов записан, вы можете щелкнуть по нему мышью и перейти к методу предка.

3 голосов
/ 11 декабря 2008

Перегрузка, сообщает компилятору, что метод имеет одно и то же имя с разными параметрами.

Переопределить, сообщает компилятору, что метод переопределяет его виртуальный или динамический, объявленный в базовом классе.

Reintroduce, скроет виртуальный или динамический метод, объявленный в базовом классе.

Определения тезисов взяты из книги Рэя Лишнера {Delphi в двух словах}

type
  TFirst = class
  private
    FValue: string;
    FNumber: Integer;
  public
    constructor Create(AValue: string; ANumber: integer);

    property MyValue: string read FValue write FValue;
    property MyNumber: Integer read Fnumber write FNumber; 
  end;

  TSecond = class(TFirst)
  public
    constructor Create(AValue: string; ANumber: Integer);
  end;

constructor TFirst.Create(AValue: string; ANumber: integer);
begin
  MyValue := AValue;
  MyNumber := ANumber;
end;

{ TSecond }

constructor TSecond.Create(AValue: string; ANumber: Integer);
begin
  inherited;
end;

TSecond, как он объявлен, будет вызывать создание TFirst, без унаследованных, члены TSecond остаются пустыми.

2 голосов
/ 11 декабря 2008

Вам нужно перегрузить оба конструктора, если они имеют одинаковые имена.

type
  TMatrix = class
  protected
    //...
  public
    constructor Create(Rows, Cols: Byte);
    //...
type
  TMinMatrix = class(TMatrix)
  public
    constructor Create(Rows, Cols: Byte); overload;
    constructor Create(var that: TMinMatrix); overload;
  end;

Хорошей практикой является вызов унаследованного конструктора.

constructor TMinMatrix.Create(Rows, Cols: Byte);
begin
   inherited Create(Rows, Cols); // Need to call the full name if the parameters are changed.
   //...
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...