"Using" is not solving the "hides virtual function" warning - overloading

I have been googling high and low and can't find a solution that will remove the warning, even when I use the using directive.
class TShowException_Form : public TForm {
__published: // IDE-managed Components
TButton *Send_Button;
TButton *Cancel_Button;
TLabel *Message_Label;
private: // User declarations
using TCustomForm::ShowModal;
//using TForm::ShowModal;
public: // User declarations
__fastcall TShowException_Form(TComponent* Owner);
int __fastcall ShowModal(System::Sysutils::Exception *E);
};
I want to hide the original virtual int __fastcall ShowModal(void) and expose a new one taking an Exception parameter.
But it still complaints on "hides virtual function":
[bcc32 Warning] TShowExceptionForm.h(32): '_fastcall TShowException_Form::ShowModal(Exception *)' hides virtual function '_fastcall TCustomForm::ShowModal()'
I have also tried using TForm::ShowModal; but with the same result.
Any ideas of how to solve this warning?
EDIT
I found out that it works perfectly well if I override the show() method instead:
class TShowException_Form : public TForm {
__published: // IDE-managed Components
TButton *Send_Button;
TButton *Cancel_Button;
TLabel *Message_Label;
private: // User declarations
using TForm::ShowModal;
using TForm::Show;
public: // User declarations
__fastcall TShowException_Form(TComponent* Owner);
int __fastcall Show(System::Sysutils::Exception *E);
};
So why isn't it working with ShowModal()?

bcc32 is, in many respects, not very compliant with the C++ standard. Whenever I find myself asking, "Why does this technique that I think should work in C++ not work in bcc32?", I usually assume it's yet another compiler bug.
The fact that Show works while ShowModal doesn't is interesting. Looking at Vcl.Forms.hpp shows the difference: Show is defined with HIDESBASE (a macro that expands to __declspec(hidesbase)).
Adding HIDESBASE to your ShowModal should work as well. You may also have to declare a virtual destructor, if you don't already have one, due to bcc32 compiler weirdness.
virtual __Fastcall ~TShowException_Form() {}

You must declare overloaded version as virtual too:
virtual int __fastcall ShowModal(System::SysUtils::Exception * E);
Does not know if C++Builder supports C++11, but if it does, try also to delete overload which you want to hide:
virtual int __fastcall ShowModal() = delete;
instead of placing it into private section.

You get the warning because what you are trying to do happens very often by mistake and is a serious and very hard to find bug if it is done by mistake. Maybe you should use a different name.

Related

BEGIN_MESSAGE_MAP caused C++ Builder 10.1 to crash to desktop

I am writing a VCL componenet, TGIcon, to mimic the Icons in windows desktop, it has been working fine until I decided to add MouseEnter and MouseLeave events to the component. I followed guides from: Embarcadero Community
and here is my code (header):
class PACKAGE TGIcon : public TGraphicControl
{
private:
AnsiString FCaption;
TPngImage *FIcon, *FDIcon;
TFont *FFont;
TNotifyEvent FOnMouseEnter;
TNotifyEvent FOnMouseLeave;
void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon)
protected:
virtual void __fastcall Paint();
void __fastcall SetCaption(AnsiString value);
void __fastcall SetIcon(TPngImage *value);
void __fastcall SetFont(TFont *value);
public:
__fastcall TGIcon(TComponent* Owner);
__fastcall ~TGIcon();
void __fastcall MakeGray(void);
__published:
__property AnsiString Caption = {read=FCaption, write=SetCaption, nodefault};
__property TPngImage *Icon = {read=FIcon, write=SetIcon};
__property TFont *Font = {read=FFont, write=SetFont};
__property Parent;
__property Enabled;
__property OnClick;
__property TNotifyEvent OnMouseEnter = {read=FOnMouseEnter, write=FOnMouseEnter};
__property TNotifyEvent OnMouseLeave = {read=FOnMouseLeave, write=FOnMouseLeave};
};
Whenever I try to place the component on a Form, the IDE (C++ Builder Starter) would crash to desktop. I have traced the source of problem to be the "BEGIN_MESSAGE_MAP...END_MESSAGE_MAP" part. If I comment out that part, the component works fine.
I used to have the same component working in C++Builder XE5 (Professional) but since that's owned by a company I no longer work with, I don't have the binary of the component, so I have to re-write it here. As far as I can remember, what I did is exactly the same as the one I wrote in XE5, that one works but this one would crash the IDE, no error message, no Access Violation, just plain CTD.
Can someone please help, is there anything I need to do to make this work in C++ Builder 10.1 (Berlin) Starter Edition? Is this a bug of C++Builder or is this what cannot be done in Starter Edition, that it only can be done in the 'paid' editions?? Or is this method already obsolete? If so please show me how the "modernized" C++ Builder do it.
Thanks in advance.
Your MESSAGE_MAP is terminated incorrectly. In the END_MESSAGE_MAP macro, you must specify the base class that your component derives from (TGraphicControl).
A MESSAGE_MAP is just a fancy way to override the virtual Dispatch() method, where:
BEGIN_MESSAGE_MAP declares and opens the overridden method, and opens a switch statement
MESSAGE_HANDLER (use VCL_MESSAGE_HANDLER instead if your project uses ATL) declares case statements for the switch
END_MESSAGE_MAP calls the Dispatch() method of the specified class for unhandled messages, closes the switch, and closes the overridden method.
Here are the declarations from sysmac.h:
#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \
{ \
switch (((PMessage)Message)->Msg) \
{
#define VCL_MESSAGE_HANDLER(msg,type,meth) \
case msg: \
meth(*((type *)Message)); \
break;
// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
// VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
// MESSAGE_HANDLER is defined as in previous versions of BCB.
//
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT
#define END_MESSAGE_MAP(base) default: \
base::Dispatch(Message); \
break; \
} \
}
So, this code:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon) // <-- error!
Gets translated by the preprocessor to this code, which is what the compiler sees:
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case CM_MOUSEENTER:
CMMouseEnter(*((TMessage *)Message));
break;
case CM_MOUSELEAVE:
CMMouseLeave(*((TMessage *)Message));
break;
default:
TGIcon::Dispatch(Message); // <-- recursive loop!
break;
}
}
As you can see, since you are specifying your own component class (TGIcon) instead of the base class (TGraphicControl) in END_MESSAGE_MAP, you are creating an endless recursion loop when the component receives an unhandled message. TGIcon::Dispatch() is calling TGIcon::Dispatch() again. It needs to call TGraphicControl::Dispatch() instead (so do your CMMouseEnter() and CMMouseLeave() methods):
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!

C++ linker warning because of virtual destructor / clang

I'm getting a linker warning caused by virtual destructors. My environment is the KEIL compiler v6.5 (clang).
Warning: L6439W: Multiply defined Global Symbol __clang_call_terminate defined in invalid_group(new.cpp.o) rejected in favor of Symbol defined in .text.__clang_call_terminate(cxa_handlers.cpp.o).
I get this warning as soon as I add the virtual destructor to an interface. For example:
class IInterface {
virtual ~IInterface(){}
virtual void doSomething() const = 0;
}
As soon as I implement one single derived class of this interface I get the above mentioned warning. As soon as I remove the virtual destructor, the warning vanishes.
I tried really many things to find out what's the reason, but didn't succeed...
Does someone know how to fix this warning?
Thank you!
Edit: A complete example throwing this warning:
class IInterface {
public:
virtual ~IInterface();
virtual void doSomething() = 0;
};
IInterface::~IInterface() {
}
class SomeClass : public IInterface {
public:
virtual void doSomething();
};
void SomeClass::doSomething() {
}
int main() {
}
I asked support of ARM and got the information that this warning is spurious. So it seems to be an issue of the current ARM clang compiler toolchain implementation.
Nevertheless thank you all for your responses on this topic.
If you define your function in header you will emit the function each time you include it in a file. To remove this warming you need to define your method outside the declaration
// IInterface.hpp
class IInterface {
public:
virtual ~IInterface();
}
// IInterface.cpp
IInterface::~IInterface() {}
As mentioned, this was a linker bug which has been fixed in ARM Compiler v6.11 (10/25/2018).
Release notes:
[SDCOMP-30157] In certain circumstances, after discarding a section from a COMDAT ELF section group, the linker could incorrectly report Warning: L6439W: Multiply defined Global Symbol defined in invalid_group() rejected in favour of Symbol defined in (). This has been fixed.

how to inherit dialogs correctly in MFC

I am building a 3d painter in C++ with OpenGL and MFC.
I created dialogs for creating every shape that i have: like cube, cylinder and etc...
My cube class inherits the cylinder class with the difference of amount of stack and slices only.
Hence the CreateCylinder dialog should look the same as the CreateCube dialog.
I was able to inherit it fine, but i have an error that says:
Error 6 error C2065: 'IDD_BASEWIN_DIALOG' : undeclared identifier c:\users\l122\desktop\opengl\opengl\basewindlg.h 19 1 OpenGL
This happens every new compilation after some minor code changes.
To fix it, i comment this line:
enum { IDD = IDD_BASEWIN_DIALOG };
then compile and uncomment the same line, which helps in the next compilation to work fine.
That how i inherited the CreateCylinder dialog class in my CreateCube dialog class:
IMPLEMENT_DYNAMIC(CreateCube, CreateCylinder)
CreateCube::CreateCube()
: CreateCylinder(this->GetSafeOwner())
{
}
CreateCube::~CreateCube()
{
}
void CreateCube::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
CreateCylinder::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CreateCube, CreateCylinder)
END_MESSAGE_MAP()
and i also edited this line in the CreateCylinder constructor:
CreateCylinder::CreateCylinder(CWnd* pParent /*=NULL*/)
: CDialogEx(CreateCylinder::IDD, this->GetSafeOwner())
The header file:
#pragma once
#include "CreateCylinder.h"
// CreateCube dialog
class CreateCube : public CreateCylinder
{
DECLARE_DYNAMIC(CreateCube)
public:
CreateCube(); // standard constructor
virtual ~CreateCube();
// Dialog Data
enum { IDD = IDD_CREATE_CUBE_DLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
};
I want to know what have i done wrong with the inheritance. is it necessary to send parent's pointer to the base dialog as i did?
And is the error above has to do anything with it?
The problem here is the scope of the enum symbol IDD_CREATE_CUBE_DLG. When you inherit a class, you don't inherit it's "symbol scope", you merely inherit its "members namespace". I'm sure some language lawyer can give a more precise (technically correct) explanation. But, a simple explanation is that you don't inherit symbol - thus enum - definitions. You should be able to access them even if they are in protected scope, though.
So, assuming that IDD_CREATE_CUBE_DLG is used in CreateCylinder class to set "its" IDD, then, instead of:
enum { IDD = IDD_CREATE_CUBE_DLG };
you should write:
enum { IDD = CreateCylinder::IDD };
I think that the correct wording would be to say that you need the "fully qualified" name here.
This is actually a good thing, and some class libraries use it to play tricks, like enumerating messages supported by a class, and such - see, for example, the FOX (widget) toolkit library.
UPDATE:
If you change your declaration as is updated here, thus avoiding the use of IDD_CREATE_CUBE_DLG, it's probable that you won't have problems with IDD_CREATE_CUBE_DLG any more. But, if you still do, the problem would be that IDD_CREATE_CUBE_DLG, since it's declared in Resource.h, then, at the time it was used (which is the line for which the error is reported), the Resource.h wasn't (properly) included. So, check what is the .cpp file that is compiled when your error is reported. Then check the includes in that file. You should clean them up, but, for starters, you may "just" #include "Resource.h" at the top (of the .h file).
As for the constructor of CDialogEx, just pass the parameter along, like this:
CreateCylinder::CreateCylinder(CWnd* pParent)
: CDialogEx(CreateCylinder::IDD, pParent)
Actually adding resource.h to my base dialog header solved the problem. I just can't understand how it worked flawlessly, before i have added the inherited classes. In both cases this header file wasn't included, so how did it work in a first place?

C++ How to ignore defined method in header file?

i want a compiler (MinGW g++/Linux g++) to ignore some defined stuff in a header file:
class A {
public:
A();
virtual ~A();
IGNORE void methodA(); // = 0 -> not possible
IGNORE void methodB(); // = 0 -> not possible
}
The problem: methodA() and methodB() can't be pure virtual because the class would be later instanciated, so it gives a compiler error. The reason for doing that: i want to have a readable header file, so this methods should be appear in files - the methods are only used as in the QT framework to work as "signals", which are translated as Strings with a macro.
May be it is possible to declare a macro to let it be as annotation? i saw this in the QT5 framework (declared signal methods) but its not working with my code...
What i not want to do: list the methods only as DOC annotation.
Thanks for a idea how to solve that ;)
void methodA(int) = delete; // note: requires C++11
void methodA(double);
will cause a compiler error if you ever try to use methodA(int), but not if you're trying to use methodA(double).
Found a way to ignore methods as described what i want to do:
#define IGNORE __attribute__((unused))
#define METHOD_TO_STRING(a) ""#a
so i can write in header files
class A {
public:
IGNORE void methodA();
void doStuff(const char *stuff);
void methodB() {
doStuff(METHOD_TO_STRING(methodA());
}
};
Now the compiler is happy and i can pass methods as args :)
Thanks for the tips

C++ Borland Builder forms - calling a function

New to C++ so sorry if this is a basic question! I am used to Java (oh yess! so easy).
My function below addMessages is called from another file, it will then actually run __fastcall TfrmRunning::Add(). As i could not get this working from the other file. the add is part of the TdrmRunning object)
How do I get the add messages to call the Add function?
This is from Running.cpp
void __fastcall TfrmRunning::Add()
{
lbMessages->Items->Add("Application Started at ");
}
//This is called from another file as i could not get the above function working
void addMessages(){
TfrmRunning::Add(); // this does not work
}
My Header file (Running.H)
class TfrmRunning : public TForm
{
__published: // IDE-managed Components
TImage *imgLogo;
TLabel *lblCopyRight;
TLabel *lblTitle;
TButton *btnExit;
TButton *btnViewType;
TListBox *lbMessages;
void __fastcall btnExitClick(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall Add();
private: // User declarations
public: // User declarations
__fastcall TfrmRunning(TComponent* Owner);
};
void addMessages();
Add() isn't a static function of TfrmRunning.
You'll need an object of type TfrmRunning to invoke it.
Try using
TObjetct *asd;
Add(asd);