7

今天最近在 Stackoverflow 上我了解到:

我一直在努力理解这一切,所以这是另一个非常具体的问题,支持我处理构造函数的主要问题


更新:替换了整个问题:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

构造 TCellPhone 时,可以使用 3 个构造函数:

  • 杯子:整数
  • 杯子:整数;茶壶:串
  • [茶壶:字符串='']

问:为什么constructor(Teapot: string='')不被隐藏?


现在我添加了第三个后代:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); override;
end;

构造TiPhone 四个构造函数时可用:

  • 杯子:整数
  • 杯子:整数
  • 杯子:整数;茶壶:串
  • [茶壶:字符串='']

为什么有四个构造函数?我覆盖了现有的三个之一。编辑:这可能是代码洞察力中的一个错误,它向我展示了四个 - 但是当两个相同时我怎么可能调用。


再次使用原始代码:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

已知TCellPhone有三个构造函数:

  • 杯子:整数
  • 杯子:整数;茶壶:串
  • [茶壶:字符串='']

如何更改声明TCellPhone以隐藏祖先构造函数?例如,这样:

TNokia = class(TCellPhone)
end;

将只有两个构造函数:

  • 杯子:整数
  • 杯子:整数;茶壶:串

现在用于reintroduce隐藏非虚拟祖先的情况。在前一种情况下TiPhone,有四个构造函数(理想情况下只有两个 - 以TComputer某种方式隐藏其祖先)。但即使我无法修复TComputer,我也可以TiPhone改为只有一个:

TComputer = class(TObject)
public
    constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer); overload; virtual;
    constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); reintroduce;
end;

现在TiPhone只有一个构造函数:

  • 杯子:整数

Reintroduce 通常只用于抑制隐藏虚拟祖先的警告。在这种情况下:

Create(Teapot: string = '')

不是虚拟的——但我仍然可以使用 reintroduce 来隐藏它。


但是现在,如果我添加另一个重载到TiPhone

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); reintroduce; overload;
   constructor Create(Handle: String); overload;
end;

然后突然(以前隐藏的)祖先回来了:

  • TiPhone.创建(7);
  • TiPhone.Create('粉红色');
  • TiPhone.Create(7, '粉红色');
  • TiPhone.Create();

如您所见,我正在努力理解

  • 当某事被隐藏时
  • 如何隐藏某事
  • 当显示某些东西时
  • 如何显示某事
4

4 回答 4

7

您不使用reintroduce隐藏祖先类的方法。您只需声明一个与祖先类中同名的方法,而无需覆盖或重载它即可。当祖先类的方法(被隐藏的方法)是虚拟的时,您可以reintroduce用来抑制Delphi 引发的警告。

如果后代的方法覆盖了祖先的方法,那么它就不会隐藏。对祖先方法的调用被路由到后代的方法。

如果后代的方法重载了祖先的方法,那么它也没有隐藏。两者都可以打电话。

于 2010-10-06T21:58:01.380 回答
1

好吧,似乎你不能在你重载的类中隐藏方法/构造函数。我带着这个小小的“黑客”来设法隐藏 TComputer 的构造函数

  TComputer = class(TObject)
  public
      constructor Create(Teapot: string='');
  end;

  THackComputer = class(TComputer)
  public
    constructor Create(Cup : Integer);virtual;
  end;

  TCellPhone = class(THackComputer)
  public
      constructor Create(Cup: Integer); overload; override;
      constructor Create(Cup: Integer; Teapot: string); overload; virtual;
  end;

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; virtual;
  end;

在该示例中,TiPhone 将只有 1 个可用的构造函数。不过,它确实打破了多态性(从 TCellPhone 隐藏第二个构造函数需要付出代价)。我想知道是否有人找到了一种在不破坏多态性的情况下这样做的方法。

另外,请注意,并不是因为代码洞察力向您显示了 4 个“构造函数”,所以确实有 4 个可用。我注意到,对于构造函数的每个“覆盖”,我都会在代码洞察力中列出 1 个构造函数。但在这种情况下,只会调用后代构造函数。

这个例子会抱怨 TCellPhone 的第二个构造函数隐藏了 THackComputer 的构造函数,但我认为这是一个误报,因为 THackComputer 的构造函数在 TCellPhone 中被覆盖。(我猜是角落案例错误,因为这不是一个非常常见的代码结构)

于 2010-10-07T17:27:38.367 回答
1

你不能覆盖一个非虚拟的方法,所以你没有隐藏任何东西。这就是为什么没有警告。

编辑:我会撤回我的断言“你没有隐藏任何东西”。我想我不太明白躲在这里的意思。我已经问过这个问题

更新:
根据我得到的答案,我想重新解释一下我的答案:由于TComputer.Constructor未声明为虚拟的,因此您已经从后代类中隐藏了该方法。因此,TCellPhone构造函数无法隐藏根本不可见的内容,因此没有编译器警告。

于 2010-10-06T21:58:44.857 回答
0

我想将此作为对 Rob Kennedy 的回答的评论,但由于我不能,所以我走了..

一直没有关于隐藏祖先构造函数的警告。

只是因为你没有。

如果我隐藏祖先,为什么没有警告?我没有重新介绍。

再一次,仅仅因为你没有隐藏任何东西。

你看到了你没有隐藏任何东西的证据。您检查过的 3 个可用构造函数就是证明。

为什么reintroduce可以用来隐藏祖先?

就像 Rob 提到的那样,重新引入只是抑制编译器提示/警告。这个词背后没有真正的技术性。因此,您不会通过重新引入来隐藏任何内容。

我想把我的想法放在如何隐藏上,但我同意 Sertac,首先我必须知道在这种情况下你对隐藏的定义是什么。

编辑:我刚刚阅读了您提到的帖子,我认为您误解了这些概念。这是我的简短解释。

reintroduce 用于隐藏祖先构造函数

该帖子的答案并未表明这一点。真正隐藏祖先构造函数的是后代的NEW CONSTRUCTOR,其参数与祖先的构造函数相同。关键字 reintroduce 只是抑制编译器警告。

reintroduce 用于显示祖先构造函数

在该帖子的答案中,使祖先的构造函数仍然可用的是 OVERLOAD 关键字。

在下面的评论中回应伊恩的问题的补充:

解决你的困惑的第一步是找出真正的问题。如果我们仔细检查您的帖子,很明显您实际上想一步解决两个问题。这两个问题是:

  1. 隐藏具有特定名称的祖先构造函数
  2. 在后代中有多个具有相同特定名称的构造函数。

虽然它们看似简单的问题,但仔细检查会立即让你想到它们的性质完全相反。问题 1 想要隐藏一个方法/构造函数,而问题 2 不仅要显示一个方法/构造函数,还要显示多个方法/构造函数。因此,如果您将它们一步混合在一起,它们肯定会相互抵消。难怪他们让你头疼...... :)

解决这两个问题的基本规则是不要将它们混为一谈。这意味着我们需要一个中间类来解决问题 1,并在该中间类的后代中进行重载。像这样的东西:

type
  TComputer = class(TObject)
  private
    FCaller: TConstructorCaller;
  public
     constructor Create(Teapot: string=''); virtual;

     property Caller: TConstructorCaller read FCaller;
  end;

  TBaseCellphone=class(TComputer)
    constructor Create(Cup: Integer); virtual;
  end;

  TCellPhone = class(TBaseCellphone)
  protected
  public
    constructor Create(Cup: Integer); overload; override;
    constructor Create(Cup: Integer; Teapot: string); overload; virtual;
  end;

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; overload;
    constructor Create(Handle: String); reintroduce; overload;
  end;

从上面的代码来看,TBaseCellphone 是中间类。在这种情况下,它的任务仅仅是隐藏 TComputer 的构造函数 Create。请注意,您不得在此处使用重载关键字,否则隐藏将被取消。现在隐藏完成后,现在您可以在其后代中自由地向您的重载关键字发送垃圾邮件,以获取多个具有相同名称的构造函数。

检查一下,你可以看到下面的代码不会编译:

   TCellPhone.Create('My Teapot');
于 2010-10-07T09:30:43.080 回答