Re: dynamic_cast<> perfomans
Kai-Uwe Bux wrote:
//C++ do not support
#define interface
//******************
//ITF0
//******************
class Base interface
{
protected:
static uint type;
public:
virtual uint itype()const {return type;}
enum { _type=0x0001 };
enum { mask=0x0001 };
};
//******************
//interface_cast
//******************
template<class Tdst,class Tsrc>
Tdst* interface_cast(Tsrc* ptr)
{
fprintf(stderr,"src: %u, dst: %u, &=%u\n", ptr->itype(), Tdst::mask,
(ptr->itype()&Tdst::mask) );
return ( ptr->itype() & Tdst::mask )?
reinterpret_cast<Tdst*>(ptr):
You need a static_cast<> or a dynamic_cast<> here. Otherwise, you invite
undefined behavior of the _serious_ sort: in the case of multiple
inheritance, casting pointers up and down really does change bit-patterns
and reinterpret_cast<> is not required to do anything like that for you.
(Of course, the return value is formally unspecified even in the case of
single inheritance.)
The dynamic_cast<> can not be used because we are making replacement for
dynamic_cast<>.
Also we are assuming case of ordinary inheritance.
Also real class of object "*ptr" is completely defined by bit-pattern so if
condition (ptr->itype()&Tdst::mask) is true, then "*ptr" is object of "Tdst"
class, so reinterpret_cast<Tdst*> is what we need here - no surprises -
address change its type to correct and I am not sure that static_cast<> will
do the same here.
Real problem here that we have no compiler support. So we must make the
bit-patterns and create data manualy, like this
protected:
static uint type;
public:
virtual uint itype()const {return type;}
enum { _type=0x0001 };
enum { mask=0x0001 };
uint Base::type=Base::_type;
and we can not control at compile time that interface_cast obtain as DST
class have declared as "interface". It is ecidently, that interface_cast can
cast only classes declared as "interface".
Yes, you do not detect some hard errors in the code, for example, here
e1=interface_cast<Derived_E1,Base>(base);
Derived_E1 is not interface, but interface_cast can cast only to interface.
I can of course, include NOT_ITF bit and detect errors at runtime, but it is
not so good as compile time.
By the way, the cast could be done without new keyword "interface_cast<>" by
"static_cast<Tdst*>(ptr)" and compiler can test at compile time that "Tdst"
is declared as "interface" and "ptr" is base for ordinary on the distance
inherited "Tdst".
But new keyword "interface_cast<>" explicit tells to compiler what to do and
especially static_cast<> assuming compile time casting, not runtime. Maybe
dynamic_cast<> can be used, but dynamic_cast<> is for MI purpose and to cast
to cncrete class, not interface.
Also it is easy to do unlimited number of inherited classes, reserving
bit-patterns
0x00000000 - not interface NOT_ITF
0xFFFFFFFF - to cast use next fild
and compiler can generate inline interface_cast
- one-if-else for number of inherited interfaces less then 32,
- two-if-else for number of inherited interfaces less then 63,
and so on, but mostly we have no more than 10-20 interfaces, inherited from
one base, so one-if-else cast will be generated.
0;
}
//******************
//******************
uint Base::type=Base::_type;
uint Derived_B1::type=Derived_A1::_type;
uint Derived_B2::type=Derived_B2::_type;
Derived_E1 *e1=0;
Derived_E3 *e3=0;
int main()
{
Base *base=new Derived_E2;
printf("%s[%p]\n","Derived_E2",base);
e1=interface_cast<Derived_E1,Base>(base);
printf("%s[%p]->%s[%p]\n","Base",base,"Derived_E1",e1);
e3=interface_cast<Derived_E3,Base>(base);
printf("%s[%p]->%s[%p]\n","Base",base,"Derived_E3",e3);
Base *const tmp=base;
base=interface_cast<Base,Derived_E3>(e3);
printf("%s[%p]->%s[%p]\n","Derived_E3",tmp,"Base",base);
}
-- cut here --
Interesting idea. However, seems to make code more difficult to maintain
since you have to implement you own mechanism keeping track of the
inheritance hierarchy.
Keeping track of the interfaces inheritance hierarchy.
Now you should measure whether a correct version (e.g., using
static_cast<>)
buys you anything in terms of speed.
There is nothing measure here. Because static_cast<> is ambiguous here. I
agree, that expression
Base *base=new Derived_E2;
e1=static_cast<Derived_E1*>(base);
is silently casted by compiler, but it is wrong, because Derived_E2 and
Derived_E1 has incompatible interfases.
Base->Derived_A1->Derived_B1->Derived_C1->Derived_E1
ITF0-> NOT_ITF ITF1->
Derived_B2->Derived_C2->Derived_E2
ITF2->
The classes have diffrents number of functions, diffrents sizeof() and so
on. It is really different classes, in spite of they have common bases
"Base" and "Derived_A1". The diffrences started at Derived_Bx point.
It seems to me, we need apply dynamic_cast<> instead of static_cast<> when
object, pointer to base class point to, is unknown at compile time. Probably
compiler can not know what kind of pointer used as "ptr" during
static_cast<>(ptr).
The dynamic_cast<> will return zero here
Base *base=new Derived_E2;
e1=dynamic_cast<Derived_E1*>(base);
but static cast not.
As for dynamic_cast<>, that I want to have correct runtime cast at the speed
as compile time cast, and dynamic_cast<> can not do it at least because
dynamic_cast<> is function and have
pushl $0
pushl $__ZTI10Derived_E1
pushl $__ZTI4Base
pushl %ebx
call ___dynamic_cast
addl $20, %esp
ret
___dynamic_cast:
enter
leave
ret
It is overhead in comparison with static_cast<> that do nothing or with
interface_cast<> that do
call virtual ptr->itype()
cmp
jmp
and I even do not whant to see what is placed between dynamic_cast<>
enter
leave
because it is more then
cmp
jmp
By the way, "virtual uint itype()const" can be replaced to increase cast
speed by non-statatic uint member, so each object of the class will contain
typeid bit-pattern. In the case differences between static_cast<> and
interface_cast<> will be
mov
cmp
jmp
that more than good for runtime casting.
I think I will add the stuff to my programs, while C++ can not do it.
--
Maksim A. Polyanin
"In thi world of fairy tales rolls are liked olso"
/Gnume/