Delphi:在子类中使用main类中的函数

时间:2014-06-24 14:38:55

标签: delphi

在编写课程的新方面,我有一些问题,我试过研究但仍然没有答案。

我想创建一个类的一个实例,它创建多个子类,创建自己的子类。我的想法是在主程序中使用这样的代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  Temp : Integer;
begin
  MainClass := TMainClass.Create(Form1);
  Temp := MainClass.SubClass1.SubSubClass1.SomeValue;
end;

主类看起来像这样,并在单独的文件中创建:

  TMainClass = class(TObject)
    private
      FSubClass1 : TSubClass1;
    public
      ValueFromAnySubClass : Integer;
      property SubClass1 : TSubClass1 read FSubClass1 write FSubClass1;
      procedure SetSomeValueFromMainClass(Value : Integer);
  end;
...
...
...
procedure TMainClass.SetSomeValueFromMainClass(Value : Integer);
begin
  ValueFromAnySubClass := Value;
end;

子类也在单独的文件中:

  TSubClass1 = class(TObject)
    private
      FSubSubClass1 : TSubSubClass1;
    public
      property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write FSubSubClass1;
  end;

现在对于子子类也在单独的文件中:

  TSubSubClass1 = class(TObject)
  private
    SomeValue : Integer;
    function  GetSomeValue : Integer;
    procedure SetSomeValue(Value : Integer);
  public
    property SomeValue : Integer read GetSomeValue write SetSomeValue;
  end;
...
...
...
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
  SetSomeValueFromMainClass(Value); <<< Error Here <<<
end;

如何使用子类中主类的函数和过程?

3 个答案:

答案 0 :(得分:3)

设计看起来很糟糕。你肯定不希望所有这些课程都了解彼此。

每次看到一行代码都包含多个.运算符时,您应该问问自己代码是否在正确的类中。通常,这表示具有多个.用途的代码行应该位于链中的其中一个类中。

但是,如果要调用方法,则需要一个实例。你写道:

procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
  SetSomeValueFromMainClass(Value);
end;

当然这不会编译。因为SetSomeValueFromMainClass不是TSubSubClass1的方法。相反,SetSomeValueFromMainClassTMainClass的方法。因此,要调用该方法,您需要一个TMainClass的实例。

这表明,如果您真的必须这样做,那么您需要向TSubSubClass1的{​​{1}}个实例提供TMainClass的实例。您可以在构造函数中提供它并记下引用。

当然,当你这样做时,你现在发现你的课程都是相互结合在一起的。有人可能想知道它们是否应该合并。

我不是说合并这些类是正确的设计。我不想就正确的设计做出任何自信的陈述。也许你需要的是一个接口,它承诺将setter作为一种解耦方法。我真的有信心说你当前的设计不是正确的设计。

答案 1 :(得分:3)

您不需要子类来使用其他类中的函数。您的示例代码也没有使用子类。 正确的子类自动访问其祖先的所有公共和保护功能。

正如David已经指出的那样,你的预期设计存在严重缺陷。

此外,根据您的评论:

  

这些类都执行完全不同的功能,但需要在一天结束时将数据写入一块硬件。数据从硬件读取并保存在内存中以便工作,直到所有工作完成后将其写回硬件组件。主类中的过程负责在任何子类需要时将实时数据写入硬件。

大卫回答:你根本不需要子类。

您需要的只是硬件类的公共方法。并且为您的其他类的每个实例提供对硬件类的正确实例的引用。

type
  THardwareDevice = class(TObject)
  public
    procedure WriteData(...);
  end;

  TOtherClass1 = class(TObject)
  private
    FDevice: THardwareDevice;
  public
    constructor Create(ADevice: THardwareDevice);

    procedure DoSomething;
  end;


constructor TOtherClass1.Create(ADevice: THardwareDevice);
begin
  FDevice := ADevice;
end;

procedure TOtherClass1.DoSomething;
begin
  //Do stuff, and maybe you need to tell the hardware to write data
  FDevice.WriteData(...);
end;

//Now given the above you can get two distinct object instances to interact
//as follows. The idea can be extended to more "other class" types and instances.
begin
  FPrimaryDevice := THardwareDevice.Create(...);
  FObject1 := TOtherClass1.Create(FPrimaryDevice);
  FObject1.DoSomething;

  //NOTE: This approach allows extreme flexibility because you can easily
  //      reference different instances (objects) of the same hardware class.
  FBackupDevice := THardwareDevice.Create(...);
  FObject2 := TOtherClass1.Create(FBackupDevice);
  FObject2.DoSomething;

  ...
end;

答案 2 :(得分:0)

据我所知,Subclass单词通常用于继承概念,但你编写的代码是一些复合类。正如您可能看到Delphi中许多类的构造函数都有一个名为AOwner的参数,可能是TComponent或TObject或......

如果您定义TSubclass1和TSubSubClass1的构造函数,如下所示,并在集函数中将您定义为属性的类的所有者更改为Self,则可以通过对所有者属性进行类型转换来访问您的TMainClass。

我将您的代码更改为您想要的工作,但我建议您更改设计。

  TSubSubClass1 = class(TObject)
  private
    FOwner: TObject;
    function GetSomeValue:Integer;
    procedure SetSomeValue(const Value: Integer);
    procedure SetOwner(const Value: TObject);
  public
    constructor Create(AOwner:TObject);reintroduce;
    property Owner:TObject read FOwner write SetOwner;
    property SomeValue : Integer read GetSomeValue write SetSomeValue;
  end;

  TSubClass1 = class(TObject)
  private
    FSubSubClass1: TSubSubClass1;
    FOwner:TObject;
    procedure SetSubSubClass1(const Value: TSubSubClass1);
    procedure SetOwner(const Value: TObject);
  public
    constructor Create(AOwner:TObject);reintroduce;
    property Owner:TObject read FOwner write SetOwner;
    property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write SetSubSubClass1;
  end;

  TMainClass = class(TObject)
  private
    FSubClass1: TSubClass1;
    procedure SetSubClass1(const Value: TSubClass1);
  public
    ValueFromAnySubClass : Integer;
    constructor Create;
    property SubClass1 : TSubClass1 read FSubClass1 write SetSubClass1;
    procedure SetSomeValueFromMainClass(Value : Integer);
  end;

实施

{ TSubSubClass1 }

constructor TSubSubClass1.Create(AOwner: TObject);
begin
  Owner:=AOwner;
end;

function TSubSubClass1.GetSomeValue: Integer;
begin
  Result:=TMainClass(TSubClass1(Self.Owner).Owner).ValueFromAnySubClass;
end;

procedure TSubSubClass1.SetOwner(const Value: TObject);
begin
  FOwner := Value;
end;

procedure TSubSubClass1.SetSomeValue(const Value: Integer);
begin
  TMainClass(TSubClass1(Self.Owner).Owner).SetSomeValueFromMainClass(Value);
end;

{ TSubClass1 }

constructor TSubClass1.Create(AOwner: TObject);
begin
  Owner:=AOwner;
  FSubSubClass1:=TSubSubClass1.Create(Self);
end;

procedure TSubClass1.SetOwner(const Value: TObject);
begin
  FOwner := Value;
end;

procedure TSubClass1.SetSubSubClass1(const Value: TSubSubClass1);
begin
  FSubSubClass1 := Value;
  FSubSubClass1.Owner:=Self;
end;

{ TMainClass }

constructor TMainClass.Create;
begin
  FSubClass1:=TSubClass1.Create(Self);
end;

procedure TMainClass.SetSomeValueFromMainClass(Value: Integer);
begin
  ValueFromAnySubClass := Value;
end;

procedure TMainClass.SetSubClass1(const Value: TSubClass1);
begin
  FSubClass1 := Value;
  FSubClass1.Owner:=Self;
end;

你必须将正确的文件名放在使用部分中。