Delphi - 智能指针构造函数的奇怪行为

标签 delphi constructor package gdi+ smart-pointers

我正在开发一个包含多个包的项目。在我的一个基础包中,我声明了一个智能指针,如下所示(这是完整的代码):

unit UTWSmartPointer;

interface

type
    IWSmartPointer<T> = reference to function: T;

    TWSmartPointer<T: class, constructor> = class(TInterfacedObject, IWSmartPointer<T>)
    private
        m_pInstance: T;

    public
        constructor Create; overload; virtual;

        constructor Create(pInstance: T); overload; virtual;

        destructor Destroy; override;

        function Invoke: T; virtual;
    end;

implementation
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create;
begin
    inherited Create;

    m_pInstance := T.Create;
end;
//---------------------------------------------------------------------------
constructor TWSmartPointer<T>.Create(pInstance: T);
begin
    inherited Create;

    m_pInstance := pInstance;
end;
//---------------------------------------------------------------------------
destructor TWSmartPointer<T>.Destroy;
begin
    m_pInstance.Free;
    m_pInstance := nil;

    inherited Destroy;
end;
//---------------------------------------------------------------------------
function TWSmartPointer<T>.Invoke: T;
begin
    Result := m_pInstance;
end;
//---------------------------------------------------------------------------

end.

后来在我的项目(以及另一个包中)中,我将此智能指针与 GDI+ 对象(TGpGraphicsPath)一起使用。我这样声明图形路径:

...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create();
...

但是,当我执行代码时,屏幕上没有绘制任何内容。我没有收到错误、没有异常或访问冲突,只是一个空白页。但如果我只是这样改变我的代码:

...
pGraphicsPath: IWSmartPointer<TGpGraphicsPath>;
...
pGraphicsPath := TWSmartPointer<TGpGraphicsPath>.Create(TGpGraphicsPath.Create);
...

然后一切都变得很好,我的路径完全按照预期绘制。但我无法弄清楚为什么第一个构造函数不能按预期工作。有人可以向我解释这种奇怪的行为吗?

问候

最佳答案

这是一个相当复杂的陷阱,你已经陷入其中了。当你写:

TGpGraphicsPath.Create

您可能认为您正在调用无参数构造函数。但事实并非如此。您实际上正在调用此构造函数:

constructor Create(fillMode: TFillMode = FillModeAlternate); reintroduce; overload;      

您不提供任何参数,因此默认值由编译器提供。

在您的智能指针类中编写:

T.Create

这实际上是在调用无参数构造函数。但这是由TObject定义的构造函数。使用该构造函数时,TGPGraphicsPath 实例未正确初始化。

如果要使用构造函数泛型约束,还必须确保始终使用可以通过无参数构造函数正确构造的类。不幸的是,TGPGraphicsPath 不符合要求。事实上,此类类别占多数。

您实际上无法在此处执行太多操作来避免显式调用构造函数。对于这个特定的类,你的智能指针类几乎不可能确定要调用哪个构造函数。

我的建议是远离构造函数通用约束并强制智能指针类的使用者显式实例化实例。

这是一个相当常见的问题 - 不到一周前我在这里回答了类似的问题:Why does a deserialized TDictionary not work correctly?

关于Delphi - 智能指针构造函数的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42254282/

相关文章:

c++ - 如何在 C++ 代码中搜索所有构造函数?

c++ - 这些对象初始化之间有什么区别?

Delphi - 在运行时创建的 TXMLDocument 生成 AV,表单上的组件正在运行

delphi - 如何从系统ImageList中绘制图像的缩放版本?

c++ - 将 const 对象显式传递给构造函数,该构造函数采用对多态类的 const 引用

linux - COTson linux安装

python - Kivy - 在 Windows 上创建包

windows - 从本地修改后的 zip 文件安装修改后的包时出错

delphi - TStringList 与 TList<string>

delphi - 防止 Delphi 包中隐式导入单元