【问题标题】:How to define a Type A in Type B and Type B in Type A?如何在Type B中定义Type A,在Type A中定义Type B?
【发布时间】:2013-01-04 10:28:46
【问题描述】:

我有两种类型。一个 A 型和一个 B 型。问题 A 型包含 B 型,B 型包含 A 型。这样的事情是行不通的:

  type
    typeA = record
       test1 : typeB;
    end;
  type
    typeB = record
       test2 : typeA;
    end;

编辑: 那不是我的设计。我将包含此类结构的 C 头文件(以访问 DLL)转换为 delphi。

编辑2: “C++ 结构是 AFAIR 类的另一个名称。一定有指针,而不是值本身。——Arioch '1 分钟前” 是的,你是对的,它是一个指向类型的指针:

我定义了:

test1 : ^typeB;

这会起作用吗?

test1 : Pointer;

编辑3: C 结构体:

/* DLPDFPAGE */
typedef struct dlpdfpage
{
    CosObj              Page;
    CosObj      PrintSelect;
    ASFixedRect         PageBBox;
    ASFixedRect         ContentBBox;
    struct dlpdfpage    *Next;
    PDRotate            Angle;
    struct dlpdfdoc     *Doc;
    DLPDFSTREAM         *Content;
    long                PageNumber;
    char                Complete;
    char                FontSubstituted;
    char                FontMM;
    char                FontBad;
} DLPDFPAGE;


/* DLPDFDOC */
typedef struct dlpdfdoc
{
    DLPDFINSTANCE       *dliInstance;
    PDDoc               pdDoc;
    CosDoc              cosDoc;
    DLPDFOUTLINE        *Outlines;
    char                *PDFFileName;
    char                *PDFPostFileName;
    DLPOS               LastPageEnd;
    DLPOS               BeforeDef;
    ASFixedRect         DocBBox;
    long                PageCount;
    long                PageTreeWidth;
    long                PageTreeDepth;
    long                PageTreeDepthUsed;
    DLPDFPAGETREEARRAY  *AllPages;
    DLPDFFONTLIST       *AllFonts;
    DLPDFFORMLIST       *AllForms;
    DLPDFFORMLIST       *AllColors;
    DLPDFIMAGELIST      *AllImages;
    DLPDFSPOTCOLORLIST  *AllSpotColors;
    DLPDFSPOTCOLORLIST  *AllPatterns;
    DLPDFEXTGSTATELIST  *AllExtGStates;
    DLPDFPAGE           *PageList;
    DLPDFPAGE           *LastPage;
    DLPDFDEST           *DeferedDests;
    DLPDFSIGNATURE      *signatureHolder;
    struct dlpdfacroform *AcroFormBase;
    CosObj              PatternColorObj,
                        PatternColorRGBObj,
                        PatternColorCMYKObj,
                        PatternColorGrayObj,
            PrintSelect,
            PrintSelectCriteria;
    CosObj      IdentH, IdentV;
    ASAtom              DocumentEncoding;
    long                FontCount;
    long                FormCount;
    long                PatCount;
    long                ImageCount;
    char                Compress;
    char                Linearize;
    char                PageTreeComplete;
    char                EmbedFonts;
    char                PatternColorsDefined;
    char                MakeThumbNails;
    ASBool              psSevenBitSafe;
    ASInt32             EncryptKeyByteCount;

    char                condenseResDicts;
    CosObj              resourceDict;  

    ASInt16             pdfMajorVer;    
    ASInt16             pdfMinorVer;    

    DLPDFINCLUDEDRES    *InclRes;       

    DLPDFSPOTCOLORLIST  *AllShadings;
    long                ShadeCount;

} DLPDFDOC;

【问题讨论】:

  • C++ 结构是 AFAIR 类的另一个名称。而且肯定有指针,而不是值本身。
  • 您应该发布原始的 C 类型声明,以便我们可以提供一些实际帮助,而不仅仅是解释您尝试的方法不起作用的原因。
  • @Arioch'The,即使C++ 结构与class 相同,C++ 类也不会自动从堆中分配,并且不会自动分配类类型的变量引用类型(与 Delphi 不同)。这不是 C++ 中的指针:aname aClassType; - 但这是:aname* aClassType;
  • 我发布了 C Sruct 部分
  • Q.E.D. - C 中的星号“*”表示指针,如 PAscal 中的“^”插入符号

标签: c delphi pointers types record


【解决方案1】:

您展示的 C 代码的 Delphi 翻译如下所示:

type
  DLPDFDOC = record; // forward declaration

  { DLPDFPAGE }
  DLPDFPAGE = record
    Page: CosObj;
    PrintSelect: CosObj;
    PageBBox: ASFixedRect;
    ContentBBox: ASFixedRect;
    Next: ^DLPDFPAGE;
    Angle: PDRotate;
    Doc: ^DLPDFDOC;
    Content: ^DLPDFSTREAM;
    PageNumber: Longint;
    Complete: AnsiChar;
    FontSubstituted: AnsiChar;
    FontMM: AnsiChar;
    FontBad: AnsiChar;
  end;

  { DLPDFDOC }
  DLPDFDOC = record
    dliInstance: ^DLPDFINSTANCE;
    pdDoc: PDDoc;
    cosDoc: CosDoc;
    Outlines: ^DLPDFOUTLINE;
    PDFFileName: PAnsiChar;
    PDFPostFileName: PAnsiChar;
    LastPageEnd: DLPOS;
    BeforeDef: DLPOS;
    DocBBox: ASFixedRect;
    PageCount: Longint;
    PageTreeWidth: Longint;
    PageTreeDepth: Longint;
    PageTreeDepthUsed: Longint;
    AllPages: ^DLPDFPAGETREEARRAY;
    AllFonts: ^DLPDFFONTLIST;
    AllForms: ^DLPDFFORMLIST;
    AllColors: ^DLPDFFORMLIST;
    AllImages: ^DLPDFIMAGELIST;
    AllSpotColors: ^DLPDFSPOTCOLORLIST;
    AllPatterns: ^DLPDFSPOTCOLORLIST;
    AllExtGStates: ^DLPDFEXTGSTATELIST;
    PageList: ^DLPDFPAGE;
    LastPage: ^DLPDFPAGE;
    DeferedDests: ^DLPDFDEST;
    signatureHolder: ^DLPDFSIGNATURE;
    AcroFormBase: ^DLPDFACROFORM;
    PatternColorObj: CosObj;
    PatternColorRGBObj: CosObj;
    PatternColorCMYKObj: CosObj;
    PatternColorGrayObj: CosObj;
    PrintSelect: CosObj;
    PrintSelectCriteria: CosObj;
    IdentH: CosObj;
    IdentV: CosObj;
    DocumentEncoding: ASAtom;
    FontCount: Longint;
    FormCount: Longint;
    PatCount: Longint;
    ImageCount: Longint;
    Compress: AnsiChar;
    Linearize: AnsiChar;
    PageTreeComplete: AnsiChar;
    EmbedFonts: AnsiChar;
    PatternColorsDefined: AnsiChar;
    MakeThumbNails: AnsiChar;
    psSevenBitSafe: ASBool;
    EncryptKeyByteCount: ASInt32;
    condenseResDicts: AnsiChar;
    resourceDict: CosObj;  
    pdfMajorVer: ASInt16;    
    pdfMinorVer: ASInt16;    
    InclRes: ^DLPDFINCLUDEDRES;       
    AllShadings: ^DLPDFSPOTCOLORLIST;
    ShadeCount: Longint;
  end;

【讨论】:

    【解决方案2】:

    你误解了那些 C 结构代表什么。这是因为 record 是一种值类型:它存储在您声明变量的位置。所以让我们做几层递归声明,你就会明白我的意思了;假设这两个结构并不完全相同:

    type
      TA = record
         test1 : TB;
         SomethingElseFromA: Byte;
      end;
    
      TB = record
         test2 : TA;
         SomethingElseFromB: Byte;
      end;   
    

    结构 TA 可以重写为:

    type
      TA = record
        // Replaced test1 : TB with the actual content of TB, because that's
        // what a record means.
        test1_test2: TA;
        test1_SomethingElseFromB: Byte;
    
        SomethingElseFromA: Byte;
      end;
    

    当然,我们现在已经很好地将 self 递归包含到 TA 记录中,类似于:

      TA = record
        // Replaces test1_test: TA
        test1_test2: TA; // Oops, still not fixed, need to do it again...
        test1_SomethingElseFromB: Byte;
        SomethingElseFromA: Byte;
    
        test1_SomethingElseFromB: Byte;
        SomethingElseFromA: Byte;
      end;
    

    您可能希望使用引用类型来获得看起来相似但并不相似的东西。引用类型始终是指针,因此它是固定大小的;编译器可以毫无问题地分配它。这将是有效的,使用指向记录的指针:

    type
      pTypeB = ^typeB;
      pTypeA = ^typeA;
    
      typeA = record
         test1 : pTypeB;
      end;
    
      typeB = record
         test2 : pTypeA;
      end;
    

    或者你可以使用类;出于同样的原因,类是引用类型;它们的工作方式与指针相同。当你声明一个指针类型的变量时,编译器分配SizeOf(Pointer)字节。


    既然你已经发布了 C 结构,我可以说它们太长了,我无法尝试完整的翻译,但我可以提出一些建议:你应该在一个 Type 块中声明所有类型;不要在每个类型声明之前写Type。这允许您在记录类型之前创建指针类型,如下所示:

    Type
      PMyRecord = ^TMyRecord;
    
      // Somewhere in the same Type block
      TMyRecord = record
      end;
    

    对于需要指向记录的指针的每种类型,首先在 Type 关键字之后声明指针,这样更简单。接下来,您需要识别 C 指针。如果数据类型名称和字段名称之间有一个*,那就是一个指针。这通常是这样写的:

    int *PointerToSomeInt;
    

    但这些也同样有效:

    int * PointerToSomeInt;
    int* VarName1, * VarName1, * VarName3; // Three pointers to integer.
    

    最后,您需要处理对齐问题。如果可以,请检查 C 端结构的大小,然后检查 Delphi 端的大小:您应该得到相同的大小。如果你不这样做,你应该在你的结构声明之前尝试几个随机的{$ALIGN} 编译器指令并重复直到你找到正确的对齐方式。如果所有其他方法都失败了,您需要找出问题所在(哪些字段在 Delphi 端的对齐方式不同)并放入一些对齐字节来人为地修复它。

    【讨论】:

    • 感谢您的回答。我会这样尝试。
    • @frugi,如果这是导入 C 编写的 DLL 所必需的,那么不仅仅是编译,而是获得一个代表完全相同数据的 Pascal 数据结构,在完全相同的布局中.它不会以任何其他方式工作。请发布原始的 C 结构,因为如果我们只看到它的帕斯卡方面,我们真的无能为力。
    • 好的,谢谢你的类型 pTypeB = ^typeB; pTypeA = ^typeA; ... 解决方案。 +1 非常好:)
    • 特别重要的是:“你应该在一个类型块中声明所有类型,不要在每个类型声明之前写类型。”
    【解决方案3】:

    也许最好的解决方案是重新考虑设计。但您可能也对所谓的类的前向声明感兴趣:

    type
      TTypeB = class;
    
      TTypeA = class
        test: TTypeB;
      end;
    
      TTypeB = class
        test: TTypeA;
      end;      
    

    原文如此!这仅适用于类,不适用于记录。

    【讨论】:

    • 啊,这里没有 Delphi 来测试所以不知道记录/类限制。为你+1。不过,将值类型放在值类型中的值类型中是有道理的......不能很好地工作:)
    • 顺便说一句,安德烈亚斯,这可以用于接口吗?我知道,我可以放 IInterface 引用并进行动态转换,但我的意思是这样的技巧来获得编译时类型检查。
    • 这可能是 1974 年帕斯卡意义上的变体记录
    • @Arioch'The:不确定,但我敢打赌大卫知道。
    • 是的,@Arioch,类和接口都可以有前向声明。 Cosmin 的回答演示了 pointer 前向声明。我不确定您认为变体记录(在 1974 年的 Pascal 意义上和 2013 年的 Delphi 意义上,因为它们是相同的)会增加这个主题。
    猜你喜欢
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 2011-05-06
    • 2019-08-08
    • 2020-12-20
    • 2017-07-08
    • 1970-01-01
    相关资源
    最近更新 更多