Introduction to Delphi Programming (102): Writing C++ Friendly Delphi Code (Part 1)

The main content of this article is as follows:

  • DOs

  • Use <span>__declspec(delphireturn)</span> syntax

  • Ensure that each constructor in the hierarchy has a unique signature

  • Methods to resolve constructor overloading issues

C++ can use Delphi code. The Delphi command-line compiler uses the following switches to generate the files required for C++ to process Delphi code:

  • <span>-JL</span> switch generates a <span>.lib</span>, <span>.bpi</span>, <span>.bpl</span>, and <span>.obj</span> file from a <span>.dpk</span> file, and generates header files for all units in the package.
  • <span>-JPHNE</span> switch does the same from a <span>.pas</span> unit.

However, not all Delphi features are C++ friendly. The following lists considerations when calling Delphi runtime code from C++, including DOs and DON’Ts.

DOs

Redeclare all inherited constructors

Unlike Delphi, C++ does not inherit constructors. For example, the following code is incorrect:

class A {public:  A(int x) {}};class B: public A {};int main(void) {  B *b = new B(5);  // Error  delete b;}

The header file generation feature of the Delphi compiler recognizes this language difference and adds the missing inherited constructors to each derived class. However, these constructors also initialize the member variables of the class. If the base constructor calls a virtual method that has already initialized one of its member variables to a non-default value, this can cause issues. In particular, it is crucial to redeclare inherited constructors if the base constructor can initialize members of the class that are of type delphireturn.

Use <span>__declspec(delphireturn)</span><span> syntax</span>

<span>__declspec(delphireturn)</span> is a special declaration modifier primarily used in the C++Builder environment to support Delphi data types and language structures. This keyword is used internally, allowing classes defined with C++Builder to support object value passing from C++ to Delphi.

__declspec(delphireturn) declarator

declarator: represents the declaration part of a variable, function, or type.

Example

Assume there is a simple Delphi type that needs to be used in C++, and you want to pass an object of this class by value to another function:

Delphi Definition

type  TMyRecord = record    Value: Integer;  end;

C++ Definition and Usage

To allow the above Delphi record type to be passed by value in C++, you can define a similar struct and apply <span>__declspec(delphireturn)</span>:

struct __declspec(delphireturn) TMyRecord {  int Value;};// Example function that accepts a TMyRecord type parametervoid ProcessRecord(TMyRecord rec) {  // Process the incoming record}

Ensure that each constructor in the hierarchy has a unique signature

C++ does not support named constructors. Therefore, overloaded constructors cannot have the same or similar parameters. For example, the following code is not suitable for C++:

MyPoint = classpublic  constructor Polar(Radius, Angle: Single);  constructor Rect(X, Y: Single);end;

This example will cause a compilation error in C++:

class MyPoint : public System::TObject {public:  __fastcall MyPoint(float Radius, float Angle);  __fastcall MyPoint(float X, float Y);};

There are several methods to resolve this issue:

  • Add a virtual parameter with a default value to one of the constructors. The header file generation feature intentionally omits the default values of constructors so that the two constructors are different in C++.

Methods to resolve constructor overloading issues between C++ and Delphi. Below are detailed explanations and examples of these two methods:

Method 1: Add a Virtual Parameter

By adding a virtual parameter with a default value to one of the constructors, you can distinguish between constructors with similar parameter signatures. This method is straightforward but requires attention to passing the correct parameters during calls.

Delphi Example

MyPoint = classpublic  constructor Polar(Radius, Angle: Single);  constructor Rect(X, Y: Single; Dummy: Integer = 0);end;

C++ Example

class PASCALIMPLEMENTATION MyPoint : public System::TObject{public:    __fastcall MyPoint(float Radius, float Angle); // Polar coordinates    __fastcall MyPoint(float X, float Y, int Dummy); // Rectangular coordinates with dummy parameter};

Leave a Comment