Board index » cppbuilder » Multiple base classes not supported - now what ?

Multiple base classes not supported - now what ?


2005-08-01 01:19:52 PM
cppbuilder109
Hi there,
I'm trying to add a Read() function to the TEdit and TCheckBox (and more)
classes for my own Setup controls. Rather than to rewrite the VCL code, i've
tried to derive from the TEdit class and my own Setup base class that has a
virtual Read() function.
I'm not succeeding since the VCL does not allow me to derrive from multiple
base classes.
My code looks like this (not complete, but you'll get the idea)
class TSetupBase
{
public:
virtual void Read(void) = 0;
};
class TMySetupEditControl : public TEdit, public TSetupBase
{
void Read(void);
};
class TMySetupCheckBoxControl : public TCheckBox, public TSetupBase
{
void Read(void);
};
Then, when a form is shown that has any TSetupBase derived components on it,
it will call the Read function for all of them (Using Controls[]).
With the above code i get a compile error 'Cannot cast from TControl * to
TSetupBase *' when i try the following:
TControl *Temp = Controls[ some index ];
if( (SupEdit=dynamic_cast<TSetupBase *>(Temp)) != NULL)
SupEdit->Read();
------
I've tried the following (without success):
class TSetupBase : public TControl
{
public:
virtual void Read(void) = 0;
};
class TMySetupEditControl : public TEdit, public TSetupBase <-- NOT allowed
now
{
void Read(void);
};
Now i'm casting every control to it's separate base class and call that
class' Read() function. So whenever i create a new Setup control i must
update the code that Reads the setup information.
How can i add the Read() function ?
Thanks as always,
Richard Luteijn
 
 

Re:Multiple base classes not supported - now what ?

"Richard Luteijn" < XXXX@XXXXX.COM >wrote in message
Quote
I'm trying to add a Read() function to the TEdit and TCheckBox
(and more) classes for my own Setup controls. Rather than to rewrite
the VCL code, i've tried to derive from the TEdit class and my own
Setup base class that has a virtual Read() function. I'm not succeeding
since the VCL does not allow me to derrive from multiple base classes.
You did not say which version of BCB you are actually using, but I'm
assuming that it is not BCB6 since BCB6 does support what you are
attempting. Older versions do not, and thus if you are indeed using an
older version then you will not be able to do what you are asking for.
About the only thing you can do is move the Read() method to its own
component and then expose a property in the TEdit and TCheckBox components
that you then link to the Read() component. But then you cannot implement
per-component functionality for Read(), unless each component internally
implements a private non-inherited interface that gets passed to the Read()
component. When Read() is called, it can then call back into the actual
components via their interfaces.
Quote
Then, when a form is shown that has any TSetupBase derived components on
it,
it will call the Read function for all of them (Using Controls[]).
In the above scenerio, you could cast the Controls[] to your derived types
directly and then check if the property has been assigned.
Quote
With the above code i get a compile error 'Cannot cast from TControl * to
TSetupBase *' when i try the following:

TControl *Temp = Controls[ some index ];
if( (SupEdit=dynamic_cast<TSetupBase *>(Temp)) != NULL)
SupEdit->Read();
Such casting does not work even in BCB6. dynamic_cast does not recognize
multiple inheritance on VCL objects properly.
Quote
How can i add the Read() function ?
The short answer is that unless you are using BCB6, you cannot.
Gambit
 

Re:Multiple base classes not supported - now what ?

Thanks Remy,
"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
You did not say which version of BCB you are actually using, but I'm
assuming that it is not BCB6 since BCB6 does support what you are
attempting.
Sorry about that. I acutally do use BCB 6 (update 4 + ilink32 5.66).
What cast do i have to use then (i've tried reinterpret_cast and i get
exceptions that class XX cannot be assigned to class XX).
Thanks,
Richard
 

{smallsort}

Re:Multiple base classes not supported - now what ?

"Richard Luteijn" < XXXX@XXXXX.COM >wrote in message
Quote
Sorry about that. I acutally do use BCB 6
Then what you posted earlier should already be working fine. One of BCB6's
new features was the ability to declare a VCL component with multiple
inheritance, as long as 1 of the classes was a VCL class and the rest were
abstract interfaces. Which is exactly what you are actually using.
Quote
What cast do i have to use then
None of them. As I mentioned earlier, dynamic_cast (and the other C++-style
casts) do not work properly with VCL classes that derive from abstract
interfaces. What you can try doing, however, is calling TComponent
QueryInterface() method, or the Supports() function from the SysUtils unit,
to see if a given component implements a given interface. Your abstract
interfaces should derive from the IInterface interface and also have a GUID
assigned via the INTERFACE_UUID macro. Look at the "Inheritance and
interfaces" topic in the help file for more details.
Gambit
 

Re:Multiple base classes not supported - now what ?

Thanks again,
I've tried to do the following (without much success)
BASE CLASS:
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}")
ISupBase :
public IInterface
{
public:
virtual void __stdcall Read(void) = 0 ;
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void
**ppv) = 0;
virtual ULONG __stdcall AddRef(void) = 0;
virtual ULONG __stdcall Release(void) = 0;
};
typedef System::DelphiInterface< ISupBase>_di_ISupBase;
DERIVED CLASS:
class PACKAGE TSupEdit : public TEdit, public ISupBase
{
private:
...
public:
__fastcall TSupEdit(TComponent* Owner);
virtual void __stdcall Read(void);
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void
**ppv) <-- NOTE the **
{
return QueryInterface(IID, (void**)ppv); <--NOTE the **
(help example uses void*) and that doesn't compile
}
virtual ULONG __stdcall AddRef(void)
{
return _AddRef();
}
virtual ULONG __stdcall Release(void)
{
return _Release();
}
...
};
The code in the above package builds OK.
APPLICATION:
TComponent *Temp;
Temp = Components[ someindex ];
if( Temp->GetInterface( __uuidof(_di_ISupBase), SupBase ) )
{
SupBase->Read();
}
When i run the program as soon as the form is created (dynamically)
i get a 'class TSupEdit not found' message. Does this have something to do
with the QueryInterface ?
Thanks,
Richard
 

Re:Multiple base classes not supported - now what ?

"Richard Luteijn" < XXXX@XXXXX.COM >wrote in message
Quote
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void
**ppv) = 0;
virtual ULONG __stdcall AddRef(void) = 0;
virtual ULONG __stdcall Release(void) = 0;
Take those declarations out of your interface. They are already inherited
from IUnknown and do not need to be redeclared.
Quote
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void
**ppv) <-- NOTE the **
{
return QueryInterface(IID, (void**)ppv); <--NOTE the **
(help example uses void*) and that doesn't compile
}
You have a recursive loop. You are not casting the ppv parameter to the
proper type, so your code is going to keep calling itself in an endless
loop. You should be casting to void* instead of void**, and you should
explicitally specify the base class as well:
virtual HRESULT __stdcall QueryInterface(const GUID &IID, void **ppv)
{
return TEdit::QueryInterface(IID, (void*)ppv);
}
Quote
virtual ULONG __stdcall AddRef(void)
{
return _AddRef();
}
Likewise, specify the base class:
virtual ULONG __stdcall AddRef(void)
{
return TEdit::_AddRef();
}
Quote
virtual ULONG __stdcall Release(void)
{
return _Release();
}
Likewise:
virtual ULONG __stdcall Release(void)
{
return TEdit::_Release();
}
Quote
if( Temp->GetInterface( __uuidof(_di_ISupBase), SupBase ) )
{
SupBase->Read();
}
You need to specify the interface itself, not the DelphiInterface wrapper,
when calling __uuidof(). Also, you need to use the '&' operator in order
for your SupBase variable to be updated properly:
_di_ISupBase SupBase;
if( Temp->GetInterface(__uuidof(ISupBase), (void*)&SupBase) )
{
SupBase->Read();
}
Or, do as I told you earlier - use QueryInterface() or Supports() instead:
_di_ISupBase SupBase;
if( SUCCEEDED(Temp->QueryInterface(__uuidof(ISupBase),
(void**)&SupBase)) )
{
SupBase->Read();
}
_di_ISupBase SupBase;
if( Supports(Temp, __uuidof(ISupBase), (void*)&SupBase) )
{
SupBase->Read();
}
Quote
When i run the program as soon as the form is created (dynamically)
i get a 'class TSupEdit not found' message. Does this have something to
do with the QueryInterface ?
No.
Gambit
 

Re:Multiple base classes not supported - now what ?

Thanks very much !,
It works fine now. Much nicer (and safer) code in the application.
Since my native language is Dutch, it's not always easy to follow English on
a subject that explains something i'm not familiar with.
I used Temp->GetInterface since QueryInterface() is not accessible (C++
compiler error). Now i'm using Supports().
Richard