Re: dynamic_cast<> perfomans
Grizlyk wrote:
Kai-Uwe Bux wrote:
But if I understand you correctly you're wondering whether every node
in a tree (nodes corresponding to classes) can be assigned a number
such that NumberOf(A) >= NumberOf(B) implies that A is a parent node of
B or equal to B.
And the answer to that is no, because two unrelated nodes would have to
have either equal numbers (incorrectly implying they're the same) or
unequal numbers (incorrectly implying one is a parent node of the
other).
The question is "if no that how"? How it must be implemented (recomended
by C++ standard) to save space and high perfomance?
The standard gives no hints as to how dynamic_cast<> is to be implemented
(there is no recommended implementation); and neither does it give any
guarantees as to performance.
It is important to me -
does C++ garantee the time of dynamic_cast<> in the case of ordinary
inheritance is equal to one-two pseudo expression "if-else"
return (Base*->type_fild >= Derived*->type_fild)? Base*: 0;
or not?
In which way is this information important to you?
1.
The dynamic_cast<> is required by design, because I can not define huge
base class interface but simple interface is not enough to possible
derived.
The solution for possible manual replacement of dynamic_cast in the case
of ordinary inheritance came up to my mind, assuming that C++ will do
nothing for perfomance here.
Don't assume! Measure! You may want to google "premature optimization".
Consider:
Ok.
Let each derived from first underived base have unique number. But we no
need number, we can use single bit in bitmask
Base->Derived_A1->Derived_B1->Derived_C1->Derived_E1
Base->Derived_A1->Derived_B2->Derived_C2->Derived_E2
[class] [type] [mask]
Base 0x0001 0x0001
Derived_A1 0x0003 0x0002
#
Derived_B1 0x0007 0x0004
Derived_C1 0x000F 0x0008
Derived_E1 0x001F 0x0010
#
Derived_B2 0x0023 0x0020
Derived_C2 0x0063 0x0040
Derived_E2 0x00E3 0x0080
dynamic_cast<>() can be implemented as single if-else operator
//extern Base* ptr;
//int Derived_C1::mask==0x0008;
//dynamic_cast<Derived_C1*>(ptr)
return ( ptr->type & Derived_C1::mask )?
reinterpret_cast<Derived_C1*>(ptr):
0;
The condition is true only if ptr is Derived_C1 or Derived_E1
2.
The 32 bit unsigned can represent 32 distinct class. But fortunatelly, we
no need cast to each derived class, not each class is declaration of uniq
interface.
New interfaces are quite rare declared so 32 bits is enough, but we can
use 64 bits and two if-else operators.
All code listed below compiler easy can do itself if programmer could tell
to compiler that class declaration is new interface declaration with the
help of new keyword "interface" and "interface_cast" instead of
dynamic_cast.
Let we have several classes as declarations of base interface extentions
in the inheritance tree. Consider the following example (cut&paste it into
file):
-- cut here --
/*
Base->Derived_A1->Derived_B1->Derived_C1->Derived_E1
ITF0-> NOT_ITF ITF1->
Base->Derived_A1->Derived_B2->Derived_C2->Derived_E2
ITF2->
Base->Derived_A1->Derived_B2->Derived_C3->Derived_E3
ITF2-> NOT_ITF
Derived_C3->Derived_E4
Derived_C3->Derived_E5
Derived_C3->Derived_E6
[class] [type] [mask]
Base 0x0001 0x0001 ITF0
Derived_B1 0x0003 0x0002 ITF1
Derived_B2 0x0005 0x0004 ITF2
*/
#include <stdio.h>
typedef unsigned uint;
//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 };
};
class Derived_A1: public Base {};
//******************
//ITF1
//******************
class Derived_B1 interface: public Derived_A1
{
protected:
static uint type;
public:
uint itype()const {return type;}
enum { _type=0x0003 };
enum { mask=0x0002 };
};
class Derived_C1: public Derived_B1 {};
class Derived_E1: public Derived_C1 {};
//******************
//ITF2
//******************
class Derived_B2 interface: public Derived_A1
{
protected:
static uint type;
public:
uint itype()const {return type;}
enum { _type=0x0005 };
enum { mask=0x0004 };
};
class Derived_C2: public Derived_B2 {};
class Derived_E2: public Derived_C2 {};
class Derived_C3: public Derived_B2 {};
class Derived_E3: public Derived_C3 {};
class Derived_E4: public Derived_C3 {};
class Derived_E5: public Derived_C3 {};
class Derived_E6: public Derived_C3 {};
//******************
//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.)
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.
Now you should measure whether a correct version (e.g., using static_cast<>)
buys you anything in terms of speed.
Best
Kai-Uwe Bux