【问题标题】:How to hide the inherited TObject constructor while the class has overloaded ones?如何在类重载时隐藏继承的 TObject 构造函数?
【发布时间】:2012-12-09 19:14:48
【问题描述】:

看看这个类:

TTest = class(TObject)  
public  
  constructor Create(A:Integer);overload;  
  constructor Create(A,B:Integer);overload;  
end;

现在当我们要使用类时:

var  
  test:  TTest;  
begin  
  test:= TTest.Create; //this constructor is still visible and usable!  
end;

谁能帮我隐藏这个构造函数?

【问题讨论】:

  • 为什么要这样做?你想达到什么目的?
  • +1。我以为以前有人问过这个问题,但我发现的唯一问题几乎没有像这个那样简洁。
  • @Marjan Venema:很明显我想做一个标准的类,我的类不应该有这个默认的构造函数。
  • 我倾向于不反对我正在使用的语言/框架。只需用 reintroduce 声明它(有效地隐藏默认值)。它是否抛出异常和/或将其标记为已弃用?如果编译器接受了已弃用的内容,那么您将收到编译时警告,否则会出现运行时异常。但我看到大卫刚刚用一些有趣的想法扩展了他的答案。
  • Deprecated 非常好。你可以让编译器阻止它。

标签: delphi constructor default-constructor


【解决方案1】:

只要您重载了名为Create 的构造函数,就不能在派生自TObject 时隐藏无参数的TObject 构造函数。

这里讨论:http://www.yanniel.info/2011/08/hide-tobject-create-constructor-delphi.html

如果您准备在您的班级和TObject 之间放置另一个班级,您可以使用Andy Hausladen's trick

TNoParameterlessContructorObject = class(TObject)
strict private
  constructor Create;
end;

TTest = class(TNoParameterlessContructorObject)
public
  constructor Create(A:Integer);overload;  
  constructor Create(A,B:Integer);overload;  
end;

【讨论】:

  • Create 或 TObject 有什么特别之处,还是这条规则适用于所有与非重载、非虚拟基方法同名的重载方法?
  • 一般。派生类(即每个类)中的任何重载方法也会自动使继承的方法重载。
  • @Rob 据我所知,构造函数没有什么特别之处,CreateTObject。使用普通方法可以重现相同的行为。
  • 请注意,您仍然可以这样做:继承创建;在后代类中。
【解决方案2】:

你可以通过引入一个非重载的 Create 来隐藏继承的 Create。由于您需要两个重载的 Create,您可以使用可选的第二个参数将它们合并为一个 Create:

TTest = class(TObject)  
public  
  constructor Create(A:Integer; B: Integer = 0); 
end;

这将给出一个编译器警告,表明您正在隐藏默认的无参数构造函数。要摆脱警告,您可以像这样声明隐藏构造函数:

TTest = class(TObject)  
public  
  constructor Create(A:Integer; B: Integer = 0); reintroduce;
end;

或者,如果这不可行,您可以引入一个中间类,引入第一个创建,然后是具有重载的第二个的最终类:

preTest = class(TObject)  
public  
  constructor Create(A:Integer); reintroduce;
end;

TTest = class(preTest)  
public  
  constructor Create(A,B:Integer);overload;  
end;

【讨论】:

  • 好吧,我讨论的有点晚了,但是第一个代码 sn -p 不会引起警告,因为TObject.Create 不是虚拟的或动态的。这也是为什么reintroduce 没有效果,根本不需要的原因。
【解决方案3】:

另一种选择是在运行时使用deprecated 关键字和raise 异常。

TTest = class(TObject)  
public  
  constructor Create; overload; deprecated 'Parameterless constructor is not Supported for a TTest class';
  constructor Create(const A: Integer); overload;  
  constructor Create(const A, B: Integer); overload;  
end;

implementation

constructor TTest.Create;
begin
  raise Exception.Create('Parameterless constructor is not Supported for a TTest class.');
end;

【讨论】:

    【解决方案4】:

    通过两次继承,可以防止用户在设计时而不是运行时创建 TMySingleton 类。

    unit MySingleton;
    
    interface
    
    uses System.Classes, System.SysUtils;
    
    type
      // Constructor Block external access
      THideConstructor = class abstract
      strict protected
        constructor Create; virtual; abstract;
      end;
    
      // Switching the access to the Create function THideConstructor in TObject through the constructor Overloading
      // Declaring Create Method as a procedure to prevent class call-TMySingle.Create('string') call impossible
      TOverloadConstructor = class(THideConstructor)
      public
        procedure Create(s: string); reintroduce; overload; deprecated 'null method';
      end;
    
      TMySingleton = class sealed(TOverloadConstructor)
      private
        class var MyObj: TMySingleton;
      strict protected
        // Hiding TOverloadConstructor.Create(s: string);
        // Implement THideConstructor.Create
        constructor Create; override;
      public
        class function Obj: TMySingleton;
        function Echo(const value: string): String;
    
        destructor Destroy; override;
      end;
    
    implementation
    
    { TMySingleton }
    
    constructor TMySingleton.Create;
    begin
      // TODO
    end;
    
    destructor TMySingleton.Destroy;
    begin
       Self.MyObj := nil;
       inherited;
    end;
    
    function TMySingleton.Echo(const value: string): String;
    begin
      result := value;
    end;
    
    class function TMySingleton.Obj: TMySingleton;
    begin
      if MyObj = nil then
        MyObj := Self.Create;
      result := MyObj;
    end;
    
    { TOverloadContructor }
    
    procedure TOverloadConstructor.Create(s: string);
    begin
      // null method
    end;
    
    initialization
    
    TMySingleton.MyObj := nil;
    
    finalization
    
    if Assigned(TMySingleton.MyObj) then
      FreeAndNil(TMySingleton.MyObj);
    
    end.
    

    如果用户

    var
      Singleton: TMySingleton;
    begin
      Singleton := TMySingleton.Create;
    

    发生设计时错误。

    [dcc32 Error] Unit1.pas(33): E2625 Private member 'THideConstructor.Create' is inaccessible here MySingleton.pas(11): Related method: constructor Create;
    

    enter image description here

    此外,您看不到任何名为 Create 的自动完成提示。

    【讨论】:

      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 2016-12-05
      • 2012-11-26
      • 2012-09-03
      • 2010-09-18
      • 2015-05-25
      相关资源
      最近更新 更多