如何访问子类中的函数?

Posted

技术标签:

【中文标题】如何访问子类中的函数?【英文标题】:How to access functions in child classes? 【发布时间】:2009-07-20 18:33:21 【问题描述】:

子类可以访问父类的protected函数,但是父类不能访问子类的protected函数。

我想尽可能保持两个类的私有。父类是一个表单,并且只使用一次实例。子类中的所有函数都是静态的,它继承自父类。

如何从父类访问子类(在另一个单元)中的非公共静态方法?

编辑:

父类(第一单元):

interface

type
TParent = class
  public
    procedure Initialize;
  protected
    procedure Test; virtual;
end;

implementation

procedure TParent.Initialize;
begin
  Writeln('Initializing');
  Test;
end;

procedure TParent.Test;
begin

end;

儿童班(第二单元):

interface

uses
ParentClass;

type
TChild = class(TParent)
protected
  procedure Test;override;
end;

implementation

procedure TChild.Test;
begin
  Writeln('Test!');
end;

代码(第三单元):

var c:TParent;

begin
  try
    c := c.Create;
    c.Initialize;
    c.Free;
    Readln;
end;

输出只是“初始化”。我尝试调试它,它没有到达子类。

【问题讨论】:

它永远不会到达子类,因为您创建错误的类。将您的创建更改为 C := TChild.Create ,它将起作用。 您错误地实例化了该类。我想你之前已经被告知过。当您调用c.Create 时,编译器没有警告您吗?如果要创建TChild 的实例,则需要在该类上调用构造函数TChild.Create 【参考方案1】:

实际上有几种方法可以做到这一点,在您的父类中,创建您调用的虚拟方法,但这些方法不做任何事情。在您的子类中,覆盖这些方法。这些方法很容易被保护,但它们必须存在于父级中。

type
  TParent = class
  protected
    procedure SpecialProcessing; virtual;
  public
    procedure DoWork;
  end;

  TChild = class(TParent)
  protected
    procedure SpecialProcessing; override;
  end;

procedure TParent.DoWork;
begin
  SpecialProcessing;
end;

procedure TParent.SpecialProcessing;
begin
  // does nothing, placeholder
end;

procedure TChild.SpecialProcessing;
begin
  // do special work here
end;

我故意没有将 TParent.SpecialProcessing 抽象化。这可以做到,但前提是 TParent 永远不会被直接创建,只有后代才会被创建。抽象方法是一种未实现但用作占位符以供以后的子实现的方法。

要创建实例,请使用以下内容:

var
  C : TParent;
begin
  // Create as a TChild, which is a TParent decendant
  C := TChild.Create;
  try
    C.DoWork;
  finally
    C.Free;
  end;
end;

【讨论】:

skamradt,首先感谢您的回答!我更喜欢第一种方式,我尝试实现它,但魔法不起作用。请再次检查我的问题,我为你做了编辑【参考方案2】:

你想做的事情违反了继承中的Liskov Substitution 原则。可能有更好的方法来做到这一点。你到底想做什么?

编辑:

为什么不能从子类创建对象实例。您始终可以将其分配给父类类型的变量。这通常在工厂模式中完成。

【讨论】:

【参考方案3】:

这是不可能的。在子类中使用非公共方法的全部目的是防止类(子类除外)能够访问它们。试图解决这个问题违反了基本的面向对象原则。

我会考虑重新考虑你的设计。

【讨论】:

如果您删除答案的第一句话,我会投赞成票 - 显然,有 种方法可以绕过这些限制。您(优秀的)主要观点是,这种阴谋诡计表明存在设计问题。 有一些设计变通方法可以解决此问题,但无法从父类中直接访问子类中的私有静态方法(这是最初的问题) -因此我认为这是不可能的。【参考方案4】:

对于已经回答的人来说,我可能遗漏了一些显而易见的东西。但我认为这只是实例化正确对象的问题。

如果对象是子类的实例,父代码将调用子代码。

试试这个

var c:TChild;
begin
  c := TChild.Create;
  c.Initialize;
  c.Free;
end.

甚至

var c:TParent;
begin
  c := TChild.Create;
  c.Initialize;
  c.Free;
end.

【讨论】:

【参考方案5】:

您可以通过在创建子类时向父类注册子类来做到这一点,使用某种回调(父类上的 cattr,子类在定义时设置)。

不过,这很少是正确的做法。就像其他人所说的那样,考虑一个不同的模式。

我不是delphi coder,但是你可以在父类上设置一个公共静态变量,在子类的setup方法中设置。

这在某些情况下是有意义的(希望将消息传递给各种子类的类设置方法),但可能有更好的方法来满足您的需要。您可能想让您的问题更多地与您的代码正在解决的问题有关。

【讨论】:

@Michael,请出示一些代码,我一个人做不到你说的。谢谢!

以上是关于如何访问子类中的函数?的主要内容,如果未能解决你的问题,请参考以下文章

继承&构造函数

子类中的 Java 静态构造函数访问

允许子类快速访问/覆盖函数,但不允许同一模块中的任何其他类

在c++中的继承,如何在子类中重载成员函数

如何在 C++ 中访问向量中的子实例

super在构造函数中的运用