在编写课程的新方面,我有一些问题,我试过研究但仍然没有答案。
我想创建一个类的一个实例,它创建多个子类,创建自己的子类。我的想法是在主程序中使用这样的代码:
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;
如何使用子类中主类的函数和过程?
答案 0 :(得分:3)
设计看起来很糟糕。你肯定不希望所有这些课程都了解彼此。
每次看到一行代码都包含多个.
运算符时,您应该问问自己代码是否在正确的类中。通常,这表示具有多个.
用途的代码行应该位于链中的其中一个类中。
但是,如果要调用方法,则需要一个实例。你写道:
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value);
end;
当然这不会编译。因为SetSomeValueFromMainClass
不是TSubSubClass1
的方法。相反,SetSomeValueFromMainClass
是TMainClass
的方法。因此,要调用该方法,您需要一个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;
你必须将正确的文件名放在使用部分中。