3

我需要创建类似的东西,我用 PHP 语言实现。

假设我创建了一个定义 2 个静态成员变量的基类,然后子类应该能够“覆盖”它们,所以如果我在 BaseClass 中定义了静态变量“someStatic”,然后我子类化为 DerivedClass,当我调用 TDerivedOne.someStatic,程序应该显示派生类的 someStatic.. 但 Delphi 不是这种情况,我肯定是错误地实现了它..

目前,我实现了另一种设计方法,其中变量没有声明为静态,然后创建了一个名为'setup'的虚拟抽象方法,然后这个setup会在BaseClass构造函数上调用,但是这个设计需要创建的对象首先在我们可以检索所需的变量之前。

现在出于好奇,我想知道是否可以实现虚拟静态变量来节省“几次打字……”

这是问题的代码片段

program Project1;

{$APPTYPE CONSOLE}


uses
    SysUtils;


type
    TBaseClass = class
      protected
        class var someStatic: string;

      public
        class function get: string; virtual;
    end;

    TDerived = class( TBaseClass )
      (*
      //if i uncomment this section, then the print bellow will print the Base's static var
      protected
        class var someStatic: string;
      *)
    end;

    TDerived2 = class( TBaseClass )
    end;

class function TBaseClass.get: string;
begin
    Result := someStatic;
end;


begin
    // ------If the class is defined per unit, this one should be on the initialization section
    TBaseClass.someStatic := 'base';
    TDerived.someStatic := 'derived';
    TDerived2.someStatic := 'derived2';
    // ------END OF INITIALIZATION

    try
        //i'm expecting this would print 'derived' but it prints 'derived2' :'(
        //i am using DelphiXE
        //apparently delphi treat the statics differently from that of php's
        writeln( TDerived.get );
        readln;
    except
        on E: Exception do
            writeln( E.ClassName, ': ', E.Message );
    end;

end.

干杯:)

4

2 回答 2

2

没问题,只要您也覆盖该Get方法:

program Project1;

{$APPTYPE CONSOLE}

type
  TBase = class
  protected
    class var FSomething: String;
    class function Get: String; virtual;
  end;

  TDerived1 = class(TBase)
  protected
    class var FSomething: String;
    class function Get: String; override;
  end;

  TDerived2 = class(TBase);

class function TBase.Get: String;
begin
  Result := FSomething;
end;

class function TDerived1.Get: String;
begin
  Result := FSomething;
end;

begin
  TBase.FSomething := 'Base';
  TDerived1.FSomething := 'Derived1';
  TDerived2.FSomething := 'Derived2';
  WriteLn(TDerived1.Get);
  ReadLn;
end.

为了可读性,我建议重命名私有字段TDerived1

或者,使用class property

program Project1;

{$APPTYPE CONSOLE}

type
  TBase = class
  private
    class var FSomething: String;
  public
    class property Something: String read FSomething write FSomething;
  end;

  TDerived1 = class(TBase)
  private
    class var FAnotherThing: String;
  public
    class property Something: String read FAnotherThing write FAnotherThing;
  end;

  TDerived2 = class(TBase);

begin
  TBase.Something := 'Base';
  TDerived1.Something := 'Derived1';
  TDerived2.Something := 'Derived2';
  WriteLn(TDerived1.Something);
  ReadLn;
end.
于 2013-07-27T10:59:46.800 回答
0

由于所有继承中的 SomeStatic 都指向同一个位置,因此将保留最后的设置。
最接近您的要求的方法可能如下所示。

type
    TBaseClass = class
      protected
        class var someStatic: string;
      public
        class function get: string; virtual;
        class Procedure _Set(const Value:String);virtual;
    end;

    TDerived = class( TBaseClass )
      protected
        class var someStatic: string;
      public
        class function get: string; override;
        class Procedure _Set(const Value:String);override;
    end;

    TDerived2 = class( TBaseClass )
      protected
        class var someStatic: string;
      public
        class function get: string; override;
        class Procedure _Set(const Value:String);override;
    end;

class function TBaseClass.get: string;
begin
    Result := someStatic;
end;


{ TDerived }

class function TDerived.get: string;
begin
    inherited;
    Result := someStatic;
end;

class procedure TDerived._Set(const Value: String);
begin
    SomeStatic := Value;
end;

{ TDerived2 }

class function TDerived2.get: string;
begin
    inherited;
    Result := someStatic;
end;

class procedure TDerived2._Set(const Value: String);
begin
  SomeStatic := Value;
end;

class procedure TBaseClass._Set(const Value: String);
begin
  SomeStatic := Value;
end;
于 2013-07-27T11:03:14.640 回答