Thursday, 22 December 2005

Delphi constructors with different names, when used in C++Builder

The integration of C++Builder and Delphi seems to have caused a few problems for those of us who write components or classes in Delphi, and then want to use these in C++Builder. There are a few things one should avoid when one writes classes (see below), and the symbol BCB doesn't seem to be defined when the Delphi compiler is called from C++Builder.

Some of the things one should not do are mentioned on the JVCL sourceforge pages.

One other thing is something I discussed elsewhere with someone. In Delphi, it is not unusual to create multiple constructors with different names which tell the user what they do.

A simple example I concocted up is below:

unit GraphicVectors;

interface

uses
  SysUtils, Classes;

type
  TGraphicVector = class(TObject)
  public
    constructor Create(X, Y: Double);
  end;

  TPolarVector = class(TGraphicVector)
  public
    constructor CreatePolar(Radial, Theta: Double);
  end;

implementation

This defines TGraphicVector, which takes two Cartesian coordinates, X and Y, both of type Double. And a descendant TPolarVector, which is internally almost the same, but can be defined using polar coordinates. So TPolarVector has two constructors, the one inherited from TGraphicVector, and CreatePolar, which accepts polar coordinates.

Constructors which differ only in name

Problem is, that both have two parameters of type Double. In Delphi, this is not a problem, because the constructors have different names. But C++ constructors do not have any names of their own. They get the name of the class for which they are defined.

So the .hpp file for the unit above contains this, for TPolarVector:

class DELPHICLASS TPolarVector;
class PASCALIMPLEMENTATION TPolarVector : public TGraphicVector
{
    typedef TGraphicVector inherited;

public:
    __fastcall TPolarVector(double Radial, double Theta);
public:
    #pragma option push -w-inl
    /* TGraphicVector.Create */ inline __fastcall
        TPolarVector(double X, double Y) : TGraphicVector(X, Y) { }
    #pragma option pop

public:
    #pragma option push -w-inl
    /* TObject.Destroy */ inline __fastcall virtual ~TPolarVector(void) { }
    #pragma option pop

};

You can see the problem above: there are two constructors TPolarvector(double, double). The first is TPolarvector.CreatePolar, the second is TGraphicVector.Create, which must be redeclared as TPolarVector to make it a constructor for TPolarVector as well. C++ does not allow two constructors with the same signature, so you will get two errors for the second declaration:

[C++ Error] GraphicVectors.hpp(49): E2238 Multiple declaration for '_fastcall TPolarVector::TPolarVector(double,double)'

[C++ Error] GraphicVectors.hpp(46): E2344 Earlier declaration of '_fastcall TPolarVector::TPolarVector(double,double)'

Conclusion

So, apart from what the JVCL pages describe, you should also avoid using constructors with the same signature but differing in name. It is best if you simply do not use any other constructor name than Create. If you need more than one, be sure to use the overload directive.

Rudy Velthuis