Reputation: 633
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?
Upvotes: 4
Views: 242
Reputation: 597885
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.
Upvotes: 4
Reputation: 2471
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.
Upvotes: 4