admin管理员组

文章数量:1289350

Now, we know that C++ constructors can not be virtual. But today I discovered something weird: the Borland compiler (bcc64) seems positive about virtual constructors, and in fact their VCL library, too (Vcl.Controls.hpp, RAD Studio 12.2):

class PASCALIMPLEMENTATION TGraphicControl : public TControl
{
    typedef TControl inherited;
    
private:
    Vcl::Graphics::TCanvas* FCanvas;
    MESSAGE void __fastcall WMPaint(Winapi::Messages::TWMPaint &Message);
    
protected:
    virtual void __fastcall Paint();
    __property Vcl::Graphics::TCanvas* Canvas = {read=FCanvas};
    
public:
    __fastcall virtual TGraphicControl(System::Classes::TComponent* AOwner);
    __fastcall virtual ~TGraphicControl();
};

In consequence, if I declare a class like:

class MyControl : public TGraphicControl
{
public:
    MyControl(TComponent *Owner);

    void __fastcall Paint() override;
};

the compiler will issue these warnings:

MyControl.h(18): 'MyControl' overrides a member function but is not marked 'override'
Vcl.Controls.hpp(2642): overridden virtual function is here

Weird! Is this some Delphi language extension? And if so, what sort of virtual member function will the compiler generate from the virtual constructor? Or is it just an inconsistency in the compiler implementation?

Now, we know that C++ constructors can not be virtual. But today I discovered something weird: the Borland compiler (bcc64) seems positive about virtual constructors, and in fact their VCL library, too (Vcl.Controls.hpp, RAD Studio 12.2):

class PASCALIMPLEMENTATION TGraphicControl : public TControl
{
    typedef TControl inherited;
    
private:
    Vcl::Graphics::TCanvas* FCanvas;
    MESSAGE void __fastcall WMPaint(Winapi::Messages::TWMPaint &Message);
    
protected:
    virtual void __fastcall Paint();
    __property Vcl::Graphics::TCanvas* Canvas = {read=FCanvas};
    
public:
    __fastcall virtual TGraphicControl(System::Classes::TComponent* AOwner);
    __fastcall virtual ~TGraphicControl();
};

In consequence, if I declare a class like:

class MyControl : public TGraphicControl
{
public:
    MyControl(TComponent *Owner);

    void __fastcall Paint() override;
};

the compiler will issue these warnings:

MyControl.h(18): 'MyControl' overrides a member function but is not marked 'override'
Vcl.Controls.hpp(2642): overridden virtual function is here

Weird! Is this some Delphi language extension? And if so, what sort of virtual member function will the compiler generate from the virtual constructor? Or is it just an inconsistency in the compiler implementation?

Share Improve this question edited Feb 21 at 10:07 AmigoJack 6,1742 gold badges19 silver badges34 bronze badges asked Feb 21 at 9:15 HendrikHendrik 6334 silver badges15 bronze badges 4
  • 3 The VCL was originally written in Delphi (which was object-oriented pascal, with some proprietary extensions). Early versions of Borland C++ used the compiled VCL directly, and needed some Borland-specific language extensions to interface to the VCL. Over time, the VCL was rewritten in C++ but (to maintain backward compatibility of code using the VCL) used those same language extensions. – Peter Commented Feb 21 at 9:52
  • Look up class references in Delphi, or in Borland C++ Builder offline help. – Igor G Commented Feb 21 at 10:00
  • 2 @Peter, the VCL is still written in Delphi Pascal. – Uli Gerhardt Commented Feb 21 at 20:25
  • 2 @Peter the VCL (and RTL and FMX, too) is still written in Delphi. It was NEVER rewritten in C++, but there are various C++ classes and C++ compiler extensions mixed in to provide compatibility between C++ and Delphi, same as it always was. – Remy Lebeau Commented Feb 21 at 20:34
Add a comment  | 

2 Answers 2

Reset to default 4

Is this some Delphi language extension?

Yes.

The following text is an excerpt from Borland C++ Wiki (uses Delphi syntax):

A constructor can be called using a variable of a class-reference type. This allows construction of objects whose type isn't known at compile time. For example:

type TControlClass = class of TControl;

function CreateControl(ControlClass: TControlClass;
const ControlName: string; X, Y, W, H: Integer): TControl;
begin
    Result := ControlClass.Create(MainForm);
    with Result do
        begin
            Parent := MainForm;
            Name := ControlName;
            SetBounds(X, Y, W, H);
            Visible := True;
        end;
end;

The CreateControl function requires a class-reference parameter to tell it what kind of control to create. It uses this parameter to call the constructor of the class. Because class-type identifiers denote class-reference values, a call to CreateControl can specify the identifier of the class to create an instance of. For example:

CreateControl(TEdit, 'Edit1', 10, 10, 100, 20);

Constructors called using class references are usually virtual. The constructor implementation activated by the call depends on the runtime type of the class reference.

In C++, such metaclass can be obtained with another Borland extension keyword: __classid:

Application->CreateForm(__classid(TForm1), &Form1);

Here, CreateForm method gets the metaclass as its first argument, and then can use that metaclass to call virtual constructor of Form1 or whichever actual visual control you want to construct.

Is this some Delphi language extension?

Yes, it is a C++ language extension for compatibility with Delphi.

In standard C++, classes are normally constructed from base-first to derived-last, which is why derived-class methods are not accessible to base-class constructors (the derived-class instance doesn't exist yet).

In Delphi, on the other hand, classes are constructed in the opposite order, from derived-first to base-last, thus derived-class methods are accessible to base-class constructors (the derived-class instance already exists), especially via polymorphic dispatch.

That is why virtual constructors can exist in Delphi classes, but not in standard C++ classes.

However, the C++ extension in question allows C++ classes which are marked with __declspec(delphiclass) (ie, they are derived from Delphi's TObject pascal class, as all VCL components are) to have virtual constructors, as they follow Delphi's creation model rather than C++'s creation model.

Most notably, per the __declspec(delphiclass) documentation:

The delphiclass argument is used to declare Delphi-style classes. Such classes are created with the following compatibility:

  • ...
  • Delphi-compatible constructor/destructor behavior
  • ...

...

Other remarks:

  • Unlike regular C++ classes, the constructors and destructors of Delphi-style base classes can invoke virtual methods and run the "most derived" implementations. Thus, it is possible that a method of a class is executed before any constructor.

本文标签: oopWhat are Borland C virtual constructorsStack Overflow