我是德尔福的新手,有着C++背景,我想弄清楚智能指针是如何实现的。我遇到了下面的帖子,我正在尝试使用它作为我自己的起点:Delphi - smart pointers and generics TList
但是,我无法使用Delphi编译前面的代码(编译器错误在代码中显示为注释)。此外,如果有人真的解释了代码的逻辑(最初我想使用这个类作为实用程序类中的一滴,但现在我想了解实际发生了什么),我会非常感激的。我模糊地理解到,由于智能指针实现是从TInterfacedObject继承的,所以引用是计数的,但除此之外的任何内容对我来说都是毫无意义的:)
unit SmartPointer;
interface
uses
SysUtils, System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
// complains ISmartPointer<T> expecting an interface type
TSmartPointer<T: class, constructor> = class(TInterfacedObject,ISmartPointer<T>)
private
FValue: T;
public
constructor Create; overload;
constructor Create(AValue: T); overload;
destructor Destroy; override;
function Invoke: T;
end;
implementation
{ TSmartPointer<T> }
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
// complains: overload procedure TSmartPointer.Create must be marked with the overload directive
constructor TSmartPointer<T>.Create(AValue: T);
begin
inherited Create;
if AValue = nil then
FValue := T.Create
else
FValue := AValue;
end;
destructor TSmartPointer<T>.Destroy;
begin
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
end.尝试使用前面的智能指针和下面的测试代码,这会导致编译器错误…我遗漏了什么?
program TestSmartPointer;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, SmartPointer;
type
TPerson = class
private
_name : string;
_age : integer;
public
property Name: string read _name write _name;
property Age: integer read _age write _age;
end;
var
pperson : TSmartPointer<TPerson>;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
pperson := TSmartPointer<TPerson>.Create();
// error on next line: undeclared Identifier: Name
pperson.Name := 'John Doe';
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.发布于 2015-04-01 18:12:22
必须将引用变量声明为ISmartPointer<TPerson>
var
pperson : ISmartPointer<TPerson>;下面的代码也会编译,但在这种情况下它不会自动释放内存,因为当您将引用计数的对象实例存储到对象引用中时,它的引用计数机制就会混乱。根据代码的不同,它可能导致内存泄漏或底层对象实例过早销毁。
var
pperson : TSmartPointer<TPerson>;
begin
pperson := TSmartPointer<TPerson>.Create();
pperson.Invoke.Name := 'John Doe';最后,下面的代码说明了正确的智能指针用法:
var
pperson : ISmartPointer<TPerson>; // note pperson is ISmartPointer<TPerson>
begin
pperson := TSmartPointer<TPerson>.Create();
pperson.Name := 'John Doe';一些接口基础
接口定义了实现接口的类必须具有的契约功能,而不提供特定的实现。IFoo接口声明意味着当您对IFoo进行引用时,可以在该引用上调用Foo方法,但这是您所能做到的全部。
IFoo = interface
procedure Foo;
end;当类实现接口时,它必须实现该接口中的所有方法。来自IFoo的方法Foo将映射到来自TFoo或TOtherFoo的方法Foo。在不同的类中,特定接口的实现可能不同。
TFoo = class(TInterfacedObject, IFoo)
public
procedure Foo;
procedure Bar;
end;
TOtherFoo = class(TInterfacedObject, IFoo)
public
procedure Foo;
end;
procedure TFoo.Bar;
begin
writeln('Bar');
end;
procedure TFoo.Foo;
begin
writeln('Foo');
end;
procedure TOtherFoo.Foo;
begin
writeln('Other Foo');
end;
var
foo: IFoo;
f: TFoo;
foo := TFoo.Create;
foo.Foo; // Output -> Foo
// Compiler error -> foo is interface reference and only knows Foo from TFoo
foo.Bar;
foo := TOtherFoo.Create;
foo.Foo; // Output -> Other Foo
// Mixing object reference with reference counted object instance -> memory leaks
f := TFoo.Create;
foo.Foo; // output -> Foo
foo.Bar; // f is TFoo object reference, and it knows everything from TFoo智能指针的实际工作方式
ISmartPointer<T>被声明为匿名函数。
ISmartPointer<T> = reference to function: T;上述声明相当于与Invoke函数的接口。
ISmartPointer<T> = interface
function Invoke: T;
end;这两种方法的不同之处(我们在这里感兴趣的一种)是,对于匿名函数/方法,您不必显式调用Invoke;编译器将为您完成这一任务。
由于ISmartPointer<T>是一个匿名函数,实际上是TSmartPointer<T>类声明中的一个接口,所以Invoke方法将被映射到ISmartPointer<T>。
TSmartPointer<T: class, constructor> = class(TInterfacedObject, ISmartPointer<T>)
private
FValue: T;
public
constructor Create; overload;
constructor Create(AValue: T); overload;
destructor Destroy; override;
function Invoke: T;
end;
var
pperson : ISmartPointer<TPerson>;因此,当您在窗帘后面编写pperson.Name时,转换为pperson.Invoke函数调用,该函数调用从FValue返回TPerson实例,TPerson具有编译器可以识别的Name属性。
由于TSmartPointer<T>是一个被引用计数的类,当您使用ISmartPointer<T>引用时,底层TSmartPointer<T>对象实例以及它在FValue中包含的T实例将在ISmartPointer<T>引用超出范围时自动释放,或者在代码中将其设置为nil。
https://stackoverflow.com/questions/29378203
复制相似问题