In a Borland C++Builder non-modern 64bit codebase (bcc64) that I’m working on, a number of class definitions emit the following warning:
warning W7041: Interface ‘XXX’ does not derive from IUnknown. (Interfaces should derive from IUnknown)
This typically happens in VCL projects (Delphi-style). Minimal example:
class Base
{
public:
Base();
virtual ~Base();
virtual void interface_method() = 0;
virtual void concrete();
};
class TMyForm : public TForm, public Base
{
__published:
private:
public:
__fastcall TMyForm(TComponent* Owner);
void interface_method(); // override
};
The unit compiles and links, but emits the above warning. So far I haven’t experienced any runtime issues, so I assume it does not cause any trouble.
Main concern: Suppress the warning
Rather than interfere with the class hierarchy, I would like to suppress the warning.
I have tried:
- Compiler options UI – warning is not featured there
#pragma diagnostic ignored "-Wall"
(Clang)#pragma warn disable
(bcc32 only)
But the warning still appears. I suspect that this warning is probably a language extension specific to the Borland frameworks. Therefore, the standard compiler mechanisms might not work.
Delphi/VCL conventions
One piece of additional information related to this issue: If class Base does not have any pure virtual methods, compilation fails, as in the following, modified example:
class Base
{
public:
Base();
virtual ~Base();
};
class TMyForm : public TForm, public Base
{
__published:
private:
public:
__fastcall TMyForm(TComponent* Owner);
};
This time, the compiler issues the following error:
[bcc64 Error] test.h(21): Delphi style classes have to be derived from Delphi style classes
6
While I haven’t found a solution that works without touching the class hierarchy, and couldn’t silence the warning either, here is one solution that has minimal impact.
Background:
The article Inheritance and interfaces | C++ and Delphi Class Models covers the relevant Delphi/VCL and COM conventions for multiple (or interface) inheritance and describes possible strategies for implementing the IUnknown
interface.
Applied to the minimal example, the solution would look like this:
class Base : public IUnknown
{
public:
virtual ~Base();
virtual void abstract_method() = 0;
};
class TMyForm : public TForm, public Base
{
INTFOBJECT_IMPL_IUNKNOWN(TComponent);
__published:
private:
public:
__fastcall TMyForm(TComponent* Owner) override;
void abstract_method() override;
};
The macro INTFOBJECT_IMPL_IUNKNOWN
will take care of implementing IUnknown
using methods present in TComponent
.
If you need to inherit from Base
in a class that is not derived from TComponent
, you can derive that class can from TInterfacedObject
instead:
class CustomClass : public TInterfacedObject, public Base
{
INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
public:
void abstract_method() override;
};
If you cannot change your custom class to inherit from TInterfacedObject
or TComponent
, the only choice left is to manually implement IUnknown
. (See the above-mentioned article.)