PolywickStudio 3 Posted December 26, 2023 In the Delphi code, I did the same, create a component from TCustomControl. I add WMMouseMove windows message procedure TCustomControlButton.WMMouseMove(var Message: TWMMouseMove); begin // inherited; // how to emulate this keyword and call base class's WMMouseMove in C++ Builder? end; In C++ Builder, I am trying to build a VCL C++ Builder component. I sub-class TCustomControl. However, I cannot seem to do the same equivalent in C++ Builder. "inherited". What should I do to solve this problem? void __fastcall TCustomControlButton::WMMouseMove( Winapi::Messages::TWMMouse &Message) { // do something... TCustomControl::WMMouseMove(Message); // OR __super::WMMouseMove(Message); } I get: [bcc32c Error] something.cpp(300): 'WMMouseMove' is a private member of 'Vcl::Controls::TControl'. Vcl.Controls.hpp(1655): declared private here Share this post Link to post
Remy Lebeau 1436 Posted December 27, 2023 There is no "inherited" in C++. You need to call the base class Dispatch() method. Or override the virtual WndProc() method instead of using a MESSAGE_MAP. Share this post Link to post
PolywickStudio 3 Posted December 28, 2023 (edited) Here's the distilled Delphi code: unit exampleunit; interface uses Windows, Messages, SysUtils, Classes, VCL.Graphics, VCL.Controls, VCL.Forms, VCL.Dialogs, VCL.StdCtrls, VCL.Buttons; type TExample = class(TCustomControl) protected procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE; end; procedure Register; implementation procedure TExample.WMMouseMove(var Message: TWMMouseMove); begin // inherited; end; procedure Register; begin RegisterComponents('Samples', [TExample]); end; end. Here's the C++ code. C++ Builder is, supposed to be the equivalent of Delphi, and should allow for C++-only VCL components. In reality, all the development goes one way. Delphi exported components to C++ Builder. Here's the C++ Builder component: //--------------------------------------------------------------------------- #ifndef examplecomponentcppH #define examplecomponentcppH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <System.SysUtils.hpp> #include <Vcl.Controls.hpp> #include <Vcl.ExtCtrls.hpp> class PACKAGE TExampleCpp : public TCustomControl { private: protected: void WMMouseMove(TWMMouseMove Message); public: __fastcall TExampleCpp(TComponent *Owner); __fastcall virtual ~TExampleCpp(); }; #endif //--------------------------------------------------------------------------- #pragma hdrstop #include "examplecomponentcpp.h" //--------------------------------------------------------------------------- #pragma package(smart_init) __fastcall TExampleCpp::TExampleCpp(TComponent *Owner) : TCustomControl(Owner) { } __fastcall TExampleCpp::~TExampleCpp() { } void TExampleCpp::WMMouseMove(TWMMouseMove Message) { // what to put here that is equivalent of the Delphi version? TCustomControl::WMMouseMove(Message); } static inline void ValidCtrCheck(TExampleCpp *) { new TExampleCpp(NULL); } There is "inherited." It's called __super https://stackoverflow.com/questions/8326309/borland-delphi-alternative-to-super-keyword or (baseclass)::(procedure). The question is. In Delphi, the inherited keyword works and causes the code to go to a private procedure in controls.pas. This beaks the cannot call private procedures and functions compiler restriction in Delphi. Which is enforced in Delphi. In C++ Builder, it bugs out and [bcc32c Error] examplecomponentcpp.cpp(17): 'WMMouseMove' is a private member of 'Vcl::Controls::TControl' Vcl.Controls.hpp(1655): declared private here Why is inherited keyword not supported in C++ Builder? Does that mean, it becomes impossible to build components in C++ Builder? the same code that compiles and works, in Delphi, cannot be done in C++ Builder? Why is it, the same Delphi code, exports as a C++ Builder component works in C++ Builder? When you try to do the same thing in C++ Builder, it becomes impossible, or there are no code samples. > You need to call the base class Dispatch() method. Or override the virtual WndProc() method instead of using a MESSAGE_MAP Can you show a complete example? Edited December 28, 2023 by PolywickStudio Share this post Link to post
Remy Lebeau 1436 Posted December 28, 2023 (edited) 18 hours ago, PolywickStudio said: Here's the distilled Delphi code: ... Here's the C++ code. C++ Builder is, supposed to be the equivalent of Delphi, and should allow for C++-only VCL components. In reality, all the development goes one way. Delphi exported components to C++ Builder. Here's the C++ Builder component: ... You did not setup your C++Builder code correctly to match the functionality of the Delphi code. Here is what your C++ code would need to look like instead to directly translate the Delphi code: //--------------------------------------------------------------------------- #ifndef examplecomponentcppH #define examplecomponentcppH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Winapi.Messages.hpp> class PACKAGE TExampleCpp : public TCustomControl { protected: MESSAGE void __fastcall WMMouseMove(TWMMouseMove& Message); public: __fastcall TExampleCpp(TComponent *Owner); __fastcall virtual ~TExampleCpp(); BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOUSEMOVE, TWMMouseMove, WMMouseMove) END_MESSAGE_MAP(TCustomControl) }; #endif //--------------------------------------------------------------------------- #pragma hdrstop #include "examplecomponentcpp.h" //--------------------------------------------------------------------------- #pragma package(smart_init) __fastcall TExampleCpp::TExampleCpp(TComponent *Owner) : TCustomControl(Owner) { } __fastcall TExampleCpp::~TExampleCpp() { } void __fastcall TExampleCpp::WMMouseMove(TWMMouseMove& Message) { //... TCustomControl::Dispatch(&Message); } namespace Examplecomponentcpp { void __fastcall PACKAGE Register() { TMetaClass* classes[1] = {__classid(TExampleCpp)}; RegisterComponents("Samples", classes, 0); } } See Declaring a New Message-handling Method in Embarcadero's documentation. Note the inclusion of the MESSAGE_MAP, that is what actually hooks up the WM_MOUSEMOVE message to the WMMouseMove() method. As I mentioned earlier, an alternative would be to override the virtual TWinControl::WndProc() method instead of using a MESSAGE_MAP, eg: //--------------------------------------------------------------------------- #ifndef examplecomponentcppH #define examplecomponentcppH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Winapi.Messages.hpp> class PACKAGE TExampleCpp : public TCustomControl { protected: virtual void __fastcall WndProc(TMessage& Message); public: __fastcall TExampleCpp(TComponent *Owner); __fastcall virtual ~TExampleCpp(); }; #endif //--------------------------------------------------------------------------- #pragma hdrstop #include "examplecomponentcpp.h" //--------------------------------------------------------------------------- #pragma package(smart_init) __fastcall TExampleCpp::TExampleCpp(TComponent *Owner) : TCustomControl(Owner) { } __fastcall TExampleCpp::~TExampleCpp() { } void __fastcall TExampleCpp::WndProc(TMessage& Message) { if (Message.Msg == WM_MOUSEMOVE) { //... } TCustomControl::WndProc(Message); } namespace Examplecomponentcpp { void __fastcall PACKAGE Register() { TMetaClass* classes[1] = {__classid(TExampleCpp)}; RegisterComponents("Samples", classes, 0); } } But, that being said, in this particular situation you really should not be handling the WM_MOUSEMOVE message directly at all. Override the virtual TControl::MouseMove() method instead, eg: //--------------------------------------------------------------------------- #ifndef examplecomponentcppH #define examplecomponentcppH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> class PACKAGE TExampleCpp : public TCustomControl { protected: DYNAMIC void __fastcall MouseMove(TShiftState Shift, int X, int Y); public: __fastcall TExampleCpp(TComponent *Owner); __fastcall virtual ~TExampleCpp(); }; #endif //--------------------------------------------------------------------------- #pragma hdrstop #include "examplecomponentcpp.h" //--------------------------------------------------------------------------- #pragma package(smart_init) __fastcall TExampleCpp::TExampleCpp(TComponent *Owner) : TCustomControl(Owner) { } __fastcall TExampleCpp::~TExampleCpp() { } void __fastcall TExampleCpp::MouseMove(TShiftState Shift, int X, int Y) { //... TCustomControl::MouseMove(Shift, X, Y); } namespace Examplecomponentcpp { void __fastcall PACKAGE Register() { TMetaClass* classes[1] = {__classid(TExampleCpp)}; RegisterComponents("Samples", classes, 0); } } 18 hours ago, PolywickStudio said: There is "inherited." It's called __super https://stackoverflow.com/questions/8326309/borland-delphi-alternative-to-super-keyword or (baseclass)::(procedure). As I stated earlier, there is no equivalent to "inherited" in C++Builder. And there is no __super in C++Builder, either. Read that post again, it does not mention __super in relation to Borland/Embarcadero compilers at all, only in relation to Microsoft compilers. your only option in C++ is to specify the base class method directly. Quote In Delphi, the inherited keyword works and causes the code to go to a private procedure in controls.pas. This beaks the cannot call private procedures and functions compiler restriction in Delphi. Which is enforced in Delphi. "inherited" in a Delphi message handler has no concept of public/private at all. Note that both the base class WMMouseMove() method in TControl and the derived class WMMouseMove() method in TExample are marked with the "message" directive (see Message Methods in Embarcadero's documentation). That means they are both stored in a message dispatch table that the compiler creates for every class that has "message" handlers. Calling "inherited" in a message handler will simply call the corresponding base class method in the dispatch table. It doesn't matter whether the methods are public or private. The table is just a bunch of method pointers. Quote In C++ Builder, it bugs out and [bcc32c Error] examplecomponentcpp.cpp(17): 'WMMouseMove' is a private member of 'Vcl::Controls::TControl' Vcl.Controls.hpp(1655): declared private here As it should be, because you are doing something COMPLETELY DIFFERENT than what the Delphi code is doing. There is no message dispatch table in C++. You are trying to directly call a base class method, and such a method call is subject to the standard public/private restrictions outlined in the C++ language. In the Delphi code, that is not the case. Quote Why is inherited keyword not supported in C++ Builder? Because it can't be. C++ and Delphi are completely different languages, with their own set of rules and restrictions. Not everything translates across the language boundary, and "inherited" is one of them. There is nothing like "inherited" in C++. Quote Does that mean, it becomes impossible to build components in C++ Builder? No, of course not. Plenty of components are written in C++Builder. I've written several myself. Quote the same code that compiles and works, in Delphi, cannot be done in C++ Builder? For the most part, it can. But certain methodologies may differ due to language differences. For instance, in this case the message dispatch happens to be different between Delphi and C++. Notice the MESSAGE_MAP in my example? That overrides the virtual TObject::Dispatch() method, and is why you have to call the base class Dispatch() method if you want to pass the message to a base class handler in C++. Quote Why is it, the same Delphi code, exports as a C++ Builder component works in C++ Builder? When you try to do the same thing in C++ Builder, it becomes impossible, or there are no code samples. You are comparing apples and oranges here. You can't rationalize why one language doesn't behave the same as another language. Edited December 28, 2023 by Remy Lebeau Share this post Link to post