Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Inheriting same interface for 2 different Classes!


This question is answered.


Permlink Replies: 6 - Last Post: Aug 9, 2016 2:11 PM Last Post By: Ahmed Sayed
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Inheriting same interface for 2 different Classes!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 1:27 AM
Hi,

I am trying to inherit the same interface with 2 different delphi classes.
TObject and TDataModule.

The Interface will contain a lot of non-pure virtual functions as it will implement
a base functionality for both classes.

What I wanna achieve is something like this:
 __interface  
INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") 
IHelloWorld : public IInterface
 { 
 public: 
     virtual void __stdcall  SayHelloWorld( void );  // Has a definition
     virtual void __stdcall  SayGoodMorning( void );  // Has a definition
 };
//---------------------------------------------------------------------------
class TMyObject : public TObject, public IHelloWorld 
{
INTFOBJECT_IMPL_IUNKNOWN(TObject);
//Code here
};
//---------------------------------------------------------------------------
class TMyDataModule: public TDataModule, public IHelloWorld 
{
INTFOBJECT_IMPL_IUNKNOWN(TDataModule);
//Code here
};

But the compiler is still giving me a warning about that QueryInterface
function hides the inherited QueryInterface.

How can I fix this? i followed the instructions in this page:
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Inheritance_and_Interfaces

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Inheriting same interface for 2 different Classes!
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 10:08 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

The Interface will contain a lot of non-pure virtual functions

Then it is not a true interface, it is just another class. An interface
CANNOT define its own implementation, it MUST consist of only pure virtual
(abstract) methods and properties, it CANNOT have any data members or non-abstract
methods.

as it will implement a base functionality for both classes.

What I wanna achieve is something like this:

Sorry, but you will not be able to achieve that the way you have shown.
TObject is written in Delphi, and Delphi-based classes (which includes TDataModule)
smply do not support multiple inheritance of classes, not even in C++. A
Delphi-based class does support implementing interfaces, though:

__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}")
IHelloWorld : public IInterface
{
public:
    virtual void __stdcall  SayHelloWorld() = 0;
    virtual void __stdcall  SayGoodMorning() = 0;
};
 
class TMyObject : public TObject, public IHelloWorld
{
public:
    INTFOBJECT_IMPL_IUNKNOWN(TObject);
    virtual void __stdcall  SayHelloWorld();
    virtual void __stdcall  SayGoodMorning();
};
 
class TMyDataModule: public TDataModule, public IHelloWorld
{
public:
    INTFOBJECT_IMPL_IUNKNOWN(TDataModule);
    virtual void __stdcall  SayHelloWorld();
    virtual void __stdcall  SayGoodMorning();
};
 
...
 
void __stdcall TMyObject::SayHelloWorld()
{
    // code here...
}
 
void __stdcall TMyObject::SayGoodMorning()
{
    // code here...
}
 
void __stdcall TMyDataModule::SayHelloWorld()
{
    // code here...
}
 
void __stdcall TMyDataModule::SayGoodMorning()
{
    // code here...
}

If you want multiple classes to share a common interface implementation,
you will have to use delegation instead of inheritance, eg.

__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}")
IHelloWorld : public IInterface
{
public:
    virtual void __stdcall  SayHelloWorld() = 0;
    virtual void __stdcall  SayGoodMorning() = 0;
};
 
class HelloWorldDelegate
{
public
    void SayHelloWorld();
    void SayGoodMorning();
};
 
class TMyObject : public TObject, public IHelloWorld
{
private:
    HelloWorldDelegate HW;
public:
    INTFOBJECT_IMPL_IUNKNOWN(TObject);
    virtual void __stdcall  SayHelloWorld();
    virtual void __stdcall  SayGoodMorning();
};
 
class TMyDataModule: public TDataModule, public IHelloWorld
{
private:
    HelloWorldDelegate HW;
public:
    INTFOBJECT_IMPL_IUNKNOWN(TDataModule);
    virtual void __stdcall  SayHelloWorld();
    virtual void __stdcall  SayGoodMorning();
};
 
...
 
void HelloWorldDelegate::SayHelloWorld()
{
    // code here...
}
 
void HelloWorldDelegate::SayGoodMorning()
{
    // code here...
}
 
void __stdcall TMyObject::SayHelloWorld()
{
    HW.SayHelloWorld();
}
 
void __stdcall TMyObjct::SayGoodMorning()
{
    HW.SayGoodMorning();
}
 
void __stdcall TMyDataModule::SayHelloWorld()
{
    HW.SayHelloWorld();
}
 
void __stdcall TMyDataModule::SayGoodMorning()
{
    HW.SayGoodMorning();
}


But the compiler is still giving me a warning about that
QueryInterface function hides the inherited QueryInterface.

You are not declaring INTFOBJECT_IMPL_IUNKNOWN() as public.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Inheriting same interface for 2 different Classes!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 11:01 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks for the tip.

But what do you mean by it will not be a true interface.
I managed to make (TMyObject, TMyDataModule) to
inherit Both my interface and delphi base classes
so i guess its working OK.

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Inheriting same interface for 2 different Classes!
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 11:36 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

But what do you mean by it will not be a true interface.

In this situation, an "interface" refers to a class that has only pure-virtual
methods. What you described:

The Interface will contain a lot of non-pure virtual functions as it will
implement a base functionality for both classes.

Does not qualify as a proper interface.

I managed to make (TMyObject, TMyDataModule) to
inherit Both my interface and delphi base classes
so i guess its working OK.

A Delphi-style class (derived from TObject) can only derive from 1 concrete
class at a time. That is a Delphi limitation. However, it can implement
multiple abstract interfaces at a time.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Inheriting same interface for 2 different Classes!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 12:05 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks for the info.

But it still giving me that warning about QueryInterface,
it is working fine for the TMObject in fact i made it inherit
from TInterfacedObjct instead of TObject.

[bcc32 Warning] MyDataModuleU.h(38): W8022 
'__stdcall TMyDataModule::QueryInterface(const _GUID &,void * *)' 
hides virtual function '__stdcall TComponent::QueryInterface(const _GUID &,void *)'


And i can't cast from the interface to TMyDataModule

_di_IHelloWorld MyInterface = new TMyDataModule(this);
 
((TMyDataModule*)MyInterface)->DoAnewFunction();
 
[bcc32 Error] MainU.cpp(25): E2031 Cannot cast from '_di_IHelloWorld ' to 'TMyDataModule*'
  Full parser context


--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Inheriting same interface for 2 different Classes!
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 1:17 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

But it still giving me that warning about QueryInterface, it is
working fine for the TMObject in fact i made it inherit from
TInterfacedObjct instead of TObject.

TCppInterfacedObject would be better. It already implements the IUnknown
methods for you, so you don't need to use INTFOBJECT_IMPL_IUNKNOWN() manually.

And i can't cast from the interface to TMyDataModule

The whole point of using an interface is to hide the implementation. You
are not supposed to cast an interface to an implementing class.

In any case, you are not casting a IHelloWorld* pointer to a TMyDataModule*
pointer. You are casting a DelphiInterface class object, which cannot be
cast as-is to a class pointer. That is why your cast fails to compile.
If you really need to cast, you would need a secondary cast to get the IHelloWorld*
pointer first:

_di_IHelloWorld MyInterface = new TMyDataModule(this);
((TMyDataModule*)(IHelloWorld*)MyInterface)->DoAnewFunction();


However, it is not safe to cast an interface pointer to a implementing class
pointer (that can be done in Delphi, but not in C++, without low-level vtable
hacking). You need to avoid this kind of code in the first place.

If you really need to call methods on the implementing class, that are not
exposed via interface methods, then you need to maintain a pointer to the
original object you created:

TMyDataModule *dm = new TMyDataModule(this)
_di_IHelloWorld MyInterface = (IHelloWorld*) dm;
...
dm->DoAnewFunction();


Or, in the case of TMyDataModule (but not TMyObject), there is an alternative
solution - TDataModule derives from TComponent, which implements an IInterfaceComponentReference
interface:

_di_IHelloWorld MyInterface = new TMyDataModule(this);
...
_di_IInterfaceComponentReference ref = MyInterface;
((TMyDataModule*)ref->GetComponent())->DoAnewFunction();


If you wanted to do something similar in TMyObject, you would have to implement
it manually:

__interface INTERFACE_UUID("{9A9C1607-4815-4CF9-B2BE-FA89D64738EE}") 
IInterfaceObjectReference : public IInterface
{ 
public: 
    virtual TObject* GetObject() = 0;
};
 
typedef DelphiInterface<IInterfaceObjectReference> _di_IInterfaceObjectReference;
 
class TMyObject : public TCppInterfacedObject<IHelloWorld>, public IInterfaceObjectReference
{
public: 
    virtual TObject* GetObject() { return this; }
 
    // Code here
    void DoAnewFunction();
};
 


_di_IHelloWorld MyInterface = new TMyObject;
...
_di_IInterfaceObjectReference ref = MyInterface;
((TMyObject*)ref->GetObject())->DoAnewFunction();


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Inheriting same interface for 2 different Classes!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 9, 2016 2:11 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
thanks again that was helpful.
By the way, What did you mean by this?

However, it is not safe to cast an interface pointer to a implementing class 
pointer (that can be done in Delphi, but not in C++, without low-level vtable 
hacking). You need to avoid this kind of code in the first place.


--
The limits of my language mean the limits of my world
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02