【问题标题】:Need I to put overload or override words after the constructor declaration in derived class?我需要在派生类中的构造函数声明之后放置重载或覆盖词吗?
【发布时间】:2008-12-11 19:36:38
【问题描述】:

我有一个类层次结构,这个:

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 编程方面没有太多经验。

【问题讨论】:

  • 在我看来,所有德尔福大师现在都在工作或睡觉,所以他们无法回答
  • 不睡觉,我的电脑今天很慢。
  • 顺便说一句,我记得我的一些旧代码中的一些非常难以发现的错误是由于忘记显式调用继承的构造函数而引起的...... :)

标签: delphi inheritance constructor


【解决方案1】:

据我所知,这里有两个不同的问题:

确保子类的构造函数调用基类的构造函数

您必须显式地调用基类的构造函数:

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

确保子类的构造函数覆盖基类的构造函数

必须使子类的构造函数override 和基类的构造函数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;

我希望这能让事情更清楚......祝你好运!

【讨论】:

  • 更正:普通的构造函数而不是虚拟的,你不需要在他们的后代上使用覆盖,你不会得到编译器警告不这样做。使用虚拟构造函数(带有覆盖)的唯一(常见)情况是针对 TComponent 的后代。
  • 哦,是吗?嗯,我一定是在这个过程中错过了一些东西......所以,对于“普通”(非 TComponent)类,你可以省略虚拟/覆盖的东西,仍然调用继承,整个事情仍然有效?
  • @MikeSutton-Mike 您对 TComponent 构造函数是正确的。但是,您确实会收到编译器错误:“E2137 Method 'Create' not found in base class”
【解决方案2】:

重载,告诉编译器一个方法同名但参数不同。

Override,告诉编译器一个方法覆盖了它在基类中声明的虚拟或动态。

重新引入,会隐藏基类中声明的虚拟或动态方法。

这些定义来自 Ray Lischner 的书 {Delphi in a nutshell}

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 成员保持为空。

【讨论】:

    【解决方案3】:

    你需要显式调用继承的方法;德尔福不会为你做这件事。这是设计使然,因为在某些情况下您正在使用虚拟方法,例如,当您不想调用继承的行为时。

    另外,作为个人喜好,我喜欢完整地写出继承的调用。 (inherited Create(Rows, Cols); 而不是 inherited; 原因很简单:它使遍历代码变得更加容易。如果你有写出的方法调用,您可以按住 Control 键单击它并进入祖先方法。

    【讨论】:

      【解决方案4】:

      如果两个构造函数名称相同,则需要重载。

      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;
      

      【讨论】:

      • 可能是:
        inherited Create(Rows, Cols)?
        或者参数列表没关系,如果两个派生的列表相同和基类?
      • 如果参数列表相同,可以省略。您甚至可以省略继承构造函数的 name,只说“inherited”而不是“inherited Create”。
      猜你喜欢
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      • 2014-11-17
      相关资源
      最近更新 更多