首页 文章

在方法之前或之后是否有任何数据字段约定? (在 class 或对象或记录中)

提问于
浏览
1

当你定义一个Class(或一个带有方法的Object或Record)时,我只是想知道是否有关于数据字段是否应该出现在方法字段之前的约定?

我的意思是在以下简单例子中两个案例之间的区别 . (编辑以使具体问题更清晰)

type TWhatever = Object
      private
        a,b : Integer;
      public
        procedure SetWhatever(x,y :Integer);
        procedure ShowWhatever;
      end;

type TWhatever = Object
      public
        procedure SetWhatever(x,y :Integer);
        procedure ShowWhatever
      private
        a,b : Integer;
     end;

我总是首先使用列出数据字段的惯例,但说实话,我并不认为它有任何区别 . 然而,最近我遇到了一些不起作用的代码(不会编译),除非首先列出数据字段 .

我在这里记录了这个案例:Delphi 2006 wont allow const parameters of type record within record method?

总结是,如果将数据字段放在方法之后,那么如果对象有任何尝试将给定对象作为“const”参数传递的方法,则代码将不会编译 . 例如,这样的东西将无法编译:

procedure TWhatever.SomeMethod( const : w1: TWhatever);

显然它会在Delphi的更高版本上编译,但我已经在Delphi7和Delphi 2006上进行了测试,它也不会编译 .

只有在执行 all three 事情时才会出现此问题(数据字段为last,将object作为参数传递给方法,对此参数使用const关键字) . 因此,您可以通过从参数中删除const关键字或将数据字段放在方法之前来解决问题 .

无论如何,这个问题让我想知道这里是否有遵循惯例?

EDITED I added this to give a specific code example

以下程序无法在D7和D2006上编译:

program bugtest;
{$APPTYPE CONSOLE}
uses SysUtils;

type Tob = object
   public
    procedure setOb(const a,b: integer);
    procedure addToOb(const ob1: Tob);
    procedure printOb;
   private
    x,y : Integer;
   end;

procedure Tob.setOb(const a,b: integer);
begin
  x:=a; y:=b;
end;

procedure Tob.addToOb(const ob1: Tob);
begin
  x:=x+ob1.x; y:= y+ob1.y;
end;

procedure Tob.printOb;
begin
  writeln(x,' ',y);
end;

var r1,r2: Tob;
begin
  r1.setOb(2,3);
  r2.setOb(10,100);
  r1.addToOb(r2);
  r1.printOb;
  r2.printOb;
  readln;
end.

以下程序在D7和D2006上编译和运行完美:

program bugtest;
{$APPTYPE CONSOLE}
uses SysUtils;

type Tob = object
   private
    x,y : Integer;
   public
    procedure setOb(const a,b: integer);
    procedure addToOb(const ob1: Tob);
    procedure printOb;
   end;

procedure Tob.setOb(const a,b: integer);
begin
  x:=a; y:=b;
end;

procedure Tob.addToOb(const ob1: Tob);
begin
  x:=x+ob1.x; y:= y+ob1.y;
end;

procedure Tob.printOb;
begin
  writeln(x,' ',y);
end;

var r1,r2: Tob;
begin
  r1.setOb(2,3);
  r2.setOb(10,100);
  r1.addToOb(r2);
  r1.printOb;
  r2.printOb;
  readln;
end.

Delphi 7版本是: Delphi Personal Version 7.0 build 4.453 .

D2006版本是: Borland Delphi for MS Windows. Version 10.0.2288.42451, Update2 .

Screenshot of compiler

2 回答

  • 4

    我认为可以说有一个广泛使用的惯例 . 通常,类声明将按如下方式排列:

    TMyClass = class
      // published declarations, managed by form designer
      Component1: TMyComponent;
      procedure MyEventHandler(Sender: TObject);
    private
      FMyPrivateField: Integer;
      procedure MyPrivateMethod;
    protected
      FMyProtectedField: Integer;
      procedure MyProtectedMethod;
    public
      FMyPublicField: Integer;
      procedure MyPublicMethod;
    published
      FMyPublishedField: Integer;
      procedure MyPublishedMethod;
    end;
    

    换句话说,这些部分将首先使用表单设计者的声明进行组织,然后按照提高可见性的顺序进行组织 .

    有趣的是,其他语言也使用其他语言 . 例如,看看Google C++ style guidelines,其中部分的顺序与上述相反 .

    就个人而言,我更愿意先看公开声明 . 在阅读已经存在的代码时,我通常会以自上而下的方式阅读 . 通常在编写代码时,我发现自上而下的方法是有益的 .

    查看我的 TComplex 记录,有一个原因可以按原样对声明进行排序 . 我有一些类似的记录,其中一些是变种记录 . 例如:

    type
      TVector = record
      public
        class operator Negative(const V: TVector): TVector;
        class operator Equal(const V1, V2: TVector): Boolean;
        class operator NotEqual(const V1, V2: TVector): Boolean;
        class operator Add(const V1, V2: TVector): TVector;
        class operator Subtract(const V1, V2: TVector): TVector;
        class operator Multiply(const V: TVector; const D: Double): TVector;
        class operator Multiply(const D: Double; const V: TVector): TVector;
        class operator Divide(const V: TVector; const D: Double): TVector;
        function IsZero: Boolean;
        function IsNonZero: Boolean;
        function IsUnit: Boolean;
        function Max: Double;
        function Sum: Double;
        function Mag: Double;
        function SqrMag: Double;
        function MagNormalComponent: Double;
        procedure MakeAxisymmetric;
        class function SNaN: TVector; static;
        function GetHashCode: Integer; inline;
      public
        case Boolean of
        False:
          (X, Y, Z: Double);
        True:
          (a: array [1..3] of Double);
      end;
    

    现在,记录的变体部分必须出现在最后 . 否则,这是一个编译错误 . 所以这个记录根本没有选择 . 在确定了 TVector 和相关记录的公约后, TComplex 只是紧随其后 .

  • 1

    根据编译器, fields declarations goes before any method declaration in any class section . 即使具有相同的可见性,类上也可能有任意数量的部分 .

    例如:

    type
      TMyObject = class
      private
        FTest: Integer;
        procedure A();
      private
        FOtherTest: Integer;
        procedure B();
      end;
    

    编译,你可以争论 FOtherTest 是否在 procedure A() 之后 .

    由于这是由编译器强制执行的,因此's no way to make it other way, so I'不确定是否将其称为约定,但必须采用这种方式 .

    另一方面,

    type
      TMyObject = class
      private
        procedure A();
        FTest: Integer;
      end;
    

    不编译,错误:

    E2169方法或属性后不允许字段定义

    如果将它作为任何类型的参数传递都没关系 . 根据我的经验,如果您只是在方法之后声明任何字段,则会发出错误 .

    编辑

    在编辑问题之后,如果在具有方法的部分之后在一个不同的部分中声明了一个Field,如果该对象作为一个const参数传递给一个,那么OP表示 object (不同于一个类)不能在Delphi 7或2006中编译例程 .

    我设法在VM中运行我的旧D7,这个例子编译好了:

    enter image description here

    它使用 objectclass 声明编译,并且因为 records 没有't support methods on that version, obviously a record declaration doesn't编译 .

    Edit2

    如果对象作为const参数传递给方法,它也会编译(无论是同一个对象的方法还是其他方法)

    enter image description here

相关问题