473,406 Members | 2,956 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Is there any faster way than dynamic_cast to find the object run time type?

I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Jul 22 '05 #1
17 3322
steve wrote:
I am writing for game application. Performance is an issue.


Then use templates instead of virtual functions. They (often) trade speed
for size.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #2
"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Yea. Put the type into the base class.
Jul 22 '05 #3
Jason Heyes posted:
"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an issue.
Any advise would be appreiciated.


Yea. Put the type into the base class.


No No No! This is clearly an instance in which one would
work with a pointer to a pointer to the *DERIVED CLASS*! To
put the type in the base clase is simply ludicrious!

-JKop
Jul 22 '05 #4
steve wrote:
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Perhaps sections 15.4.4, 15.4.4.1 and 15.4.5 in TC++PL 3 can be useful
to you.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #5
steve wrote:
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Perhaps sections 15.4.4, 15.4.4.1 and 15.4.5 in TC++PL 3 can be useful
to you.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #6
PKH

"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


I'm using the following approach in a game I'm working on. By inlining the
RequestClass functions it should be quite fast. (I posted this earlier in
another thread )
typedef char ClassID;

class CClassIDBase
{
public:
static ClassID
m_cClassID;

virtual CClassIDBase* RequestClass(const ClassID& c)
{
return (&c == &m_cClassID) ? this : NULL;
}
};
class CCow : public CClassIDBase
{
public:
static ClassID
m_cClassID;

public:
void EatGrass(){}
virtual CClassIDBase* RequestClass(const ClassID& c)
{
return (&c == &m_cClassID) ? this : CClassIDBase::RequestClass(c);
}
};
class CBrow : CClassIDBase
{
public:
static ClassID
m_cClassID;

CCow
m_cCow;

public:
virtual CClassIDBase* RequestClass(const ClassID& c)
{
if (&c == &CCow::m_cClassID)
{
return &m_cCow;
}
else
{
return (&c == &m_cClassID) ? this : CClassIDBase::RequestClass(c);
}
}
};
ClassID
CClassIDBase::m_cClassID = 0,
CCow::m_cClassID = 0,
CBrow::m_cClassID = 0;
int main(int argc, char* argv[])
{
CCow
*pcCow;

CBrow
cBrow;

if ((pcCow = (CCow*)cBrow.RequestClass(CCow::m_cClassID)) != NULL)
{
pcCow->EatGrass();
}

return 0;
}

Jul 22 '05 #7
"steve" <st***@mcube.com.tw> wrote in message news:<ch**********@netnews.hinet.net>...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Well, the first bit of advice would be to carefully consider whether
you actually need to know the actual type. In general, you should try
to design things so that when you have, say, a pointer-to-Shape you
only need to do Shape things to it and don't really care whether the
object's actual type is Triangle, Ellipse, or Rhombus.

However, assuming you've already considered all that and really do
need to know the type, you have two choices: dynamic_cast and typeid.
It's possible that one is faster than the other. You should probably
test both and see.

They do slightly different things: dynamic_cast will tell you whether
the object's type is *compatible* with the specified type; typeid
tells you the specific type. The following program illustrates the
difference:

#include <iostream>

class A { public: virtual ~A() {} };
class B : public A {};
class C : public B {};

#define TEST(expr) std::cout << #expr " --> " << (expr) << '\n'

int main()
{
C obj;
A* p = &obj;
TEST( dynamic_cast<B*>(p) != 0 );
TEST( dynamic_cast<C*>(p) != 0 );
TEST( typeid(*p) == typeid(B) );
TEST( typeid(*p) == typeid(C) );
return 0;
}

The output is:

dynamic_cast<B*>(p) != 0 --> 1
dynamic_cast<C*>(p) != 0 --> 1
typeid(*p) == typeid(B) --> 0
typeid(*p) == typeid(C) --> 1

--Nick
Jul 22 '05 #8

"PKH" <no************@online.no> skrev i en meddelelse
news:FP******************@news4.e.nsc.no...

"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


I'm using the following approach in a game I'm working on. By inlining the
RequestClass functions it should be quite fast. (I posted this earlier in
another thread )


[snip]

You answered the question: is it possible to detect the object run time type
without using dynamic_cast. I see that it is. Could you also demonstrate
that it is faster than dynamic_cast? (In that case you should quote the
compiler and settings used)
/Peter
Jul 22 '05 #9

"steve" <st***@mcube.com.tw> skrev i en meddelelse
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


Just use dynamic_cast until yoy test it and find if it is to slow. Remember
that the compiler writers do try to make our programs work as fast as
possible.
/Peter
Jul 22 '05 #10
PKH

"Peter Koch Larsen" <pk*****@mailme.dk> wrote in message
news:ys********************@news000.worldonline.dk ...

"PKH" <no************@online.no> skrev i en meddelelse
news:FP******************@news4.e.nsc.no...

"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
>I am writing for game application. Performance is an issue.
>
> Any advise would be appreiciated.
>


I'm using the following approach in a game I'm working on. By inlining
the
RequestClass functions it should be quite fast. (I posted this earlier in
another thread )


[snip]

You answered the question: is it possible to detect the object run time
type
without using dynamic_cast. I see that it is. Could you also demonstrate
that it is faster than dynamic_cast? (In that case you should quote the
compiler and settings used)
/Peter


I hadn't really tested speed, but needed the extra flexibility the ClassID
approach gives.
After doing a test with upcasting from a basepointer which is what I use
most, I was pleasantly suprised.
It's is quite a lot faster in release on the following code.

On an amd 2500+, VC 6.0 for the following code, the results were

In Debug, ClassID 1.03 secs, Dynamic cast 1.34 secs
In Release ClassID 0.13 secs, Dynamic cast 0.81 secs (inline any suitable,
maximize speed)

I checked that EatGrass() was actually called for both loops in release.
Of course the compiler might do some tricks with this code when optimizing,
but I think I can conclude that ClassID is at least as fast as dynamic_cast
(unless there is some mistake in the code).
#include <windows.h>
#include <conio.h>
#include <stdio.h>
typedef char ClassID;

class CClassIDBase
{
public:
static ClassID
m_cClassID;

inline
virtual CClassIDBase* RequestClass(const ClassID& c)
{
return (&c == &m_cClassID) ? this : NULL;
}
};
class CCow : public CClassIDBase
{
public:
static ClassID
m_cClassID;

public:
void EatGrass(){}
inline
virtual CClassIDBase* RequestClass(const ClassID& c)
{
return (&c == &m_cClassID) ? this : CClassIDBase::RequestClass(c);
}
};
class CSuperCow : public CCow
{
public:
static ClassID
m_cClassID;

public:
inline
virtual CClassIDBase* RequestClass(const ClassID& c)
{
return (&c == &m_cClassID) ? this : CCow::RequestClass(c);
}
};

class CBrow : public CClassIDBase
{
public:
static ClassID
m_cClassID;

CCow
m_cCow;

public:
inline
virtual CClassIDBase* RequestClass(const ClassID& c)
{
if (&c == &CCow::m_cClassID)
{
return &m_cCow;
}
else
{
return (&c == &m_cClassID) ? this : CClassIDBase::RequestClass(c);
}
}
};
ClassID
CClassIDBase::m_cClassID = 0,
CCow::m_cClassID = 0,
CSuperCow::m_cClassID = 0,
CBrow::m_cClassID = 0;
int main(int argc, char* argv[])
{
CClassIDBase
*pcBase;

CCow
*pcCow;

CBrow
cBrow;

CSuperCow
cSuperCow;

LARGE_INTEGER
nFreq,
nStartTick,
nEndTick;

BOOL
bRes;

DWORD
i;

float
vFreq,
vClassIDSecs,
vDynamicCastSecs;

bRes = QueryPerformanceFrequency(&nFreq);
vFreq = (float)nFreq.QuadPart;

pcBase = &cSuperCow;

// Class ID
QueryPerformanceCounter(&nStartTick);

for (i = 0; i < 10000000; i++)
{
pcCow = (CCow*)pcBase->RequestClass(CCow::m_cClassID);
if (pcCow)
{
pcCow->EatGrass();
}
}

QueryPerformanceCounter(&nEndTick);
vClassIDSecs = (nEndTick.QuadPart - nStartTick.QuadPart) / vFreq;

// Dynamic_cast
QueryPerformanceCounter(&nStartTick);

for (i = 0; i < 10000000; i++)
{
pcCow = dynamic_cast<CCow*>(pcBase);
if (pcCow)
{
pcCow->EatGrass();
}
}

QueryPerformanceCounter(&nEndTick);
vDynamicCastSecs = (nEndTick.QuadPart - nStartTick.QuadPart) / vFreq;

// You can also do this, which isn't available with dynamic_cast
// since Brow doesn't inherit from cow
if ((pcCow = (CCow*)cBrow.RequestClass(CCow::m_cClassID)) != NULL)
{
pcCow->EatGrass();
}

printf("ClassID: %.2f, DynamicCast: %.2f", vClassIDSecs,
vDynamicCastSecs);

while (!_kbhit());

return 0;
}



Jul 22 '05 #11
Niklas Borson wrote:
Well, the first bit of advice would be to carefully consider whether
you actually need to know the actual type. In general, you should try
to design things so that when you have, say, a pointer-to-Shape you
only need to do Shape things to it and don't really care whether the
object's actual type is Triangle, Ellipse, or Rhombus.

However, assuming you've already considered all that and really do
need to know the type, you have two choices: dynamic_cast and typeid.
It's possible that one is faster than the other. You should probably
test both and see.

They do slightly different things: dynamic_cast will tell you whether
the object's type is *compatible* with the specified type; typeid
tells you the specific type. The following program illustrates the
difference:

#include <iostream>

class A { public: virtual ~A() {} };
class B : public A {};
class C : public B {};

#define TEST(expr) std::cout << #expr " --> " << (expr) << '\n'

int main()
{
C obj;
A* p = &obj;
TEST( dynamic_cast<B*>(p) != 0 );
TEST( dynamic_cast<C*>(p) != 0 );
TEST( typeid(*p) == typeid(B) );
TEST( typeid(*p) == typeid(C) );
return 0;
}

The output is:

dynamic_cast<B*>(p) != 0 --> 1
dynamic_cast<C*>(p) != 0 --> 1
typeid(*p) == typeid(B) --> 0
typeid(*p) == typeid(C) --> 1


One of the interesting things in the chapters that I mentioned in
another message is:
"15.4.5 Uses and Misuses of RTTI

One should use explicit run-time type information only when necessary.
Static (compile-time) checking is safer, implies less overhead, and –
where applicable – leads to better structured programs.

For example, RTTI can be used to write thinly disguised switch-statements:

// misuse of runtime

type information:
void rotate(const Shape& r)
{
if (typeid(r) == typeid(Circle)) {
// do nothing
}

else if (typeid(r) == typeid(Triangle)) {
// rotate triangle
}
else if (typeid(r) == typeid(Square)) {
// rotate square
}
// ...
}
Using dynamic_cast rather than typeid would improve this code only
marginally.

Unfortunately, this is not a strawman example; such code really does get
written. For many people trained in languages such as C, Pascal,
Modula2,and Ada, there is an almost irresistible urge to organize
software as a set of switch-statements. This urge should usually be
resisted. Use virtual functions (§2.5.5, §12.2.6) rather than RTTI to
handle most cases when run-time discrimination based on type is needed."
And other useful stuff.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #12
Hi,
I am writing for game application. Performance is an issue.
Any advise would be appreiciated.


typeid(...) should be a lot faster than dynamic_cast if your class hierarchy
is large, and especially if you are using multiple or virtual inheritance.
From my experience with Visual C++, dynamic_cast on a large
multi-virtual-hierarchy could take as much as 5000 cpu cycles to execute,
while typeid cost is similar to virtual function call.

Anyway, using too much dynamic type checking in your code usually indicates
a design flaw. You should have designed for static type checking instead.

Best regards,
Marcin
Jul 22 '05 #13
"steve" <st***@mcube.com.tw> wrote in message news:<ch**********@netnews.hinet.net>...
I am writing for game application. Performance is an issue.

Any advise would be appreiciated.


I don't think you should avoid the dynamic_cast when casting the
base class pointer/reference to the concrete class.

We are using the following pattern:

class Base {
public:
enum Type {
typeA = 1,
typeB,
// ...
typeX
};
public:
virtual Type type() const = 0;
};

class TypeA : public Base {
public:
Type type() const { return typeA; }
};

// downcasting
void showBase(const Base& base)
{
switch (base.type()) {
case Base::typeA: {
const TypeA* typeA = dynamic_cast<const TypeA*>(base);
if (0 == typeA) throw ...; // somebody cheats!
typeA->typeASpecific();
}
// other cases
...
// no default: let compiler warn
}
}

In the real code things are somewhat more complicated, basically
in order to allow declaration of Base::Type without the need to
include the header file.

Stephan Brönnimann
br****@osb-systems.com
Open source rating and billing engine for communication networks.
Jul 22 '05 #14
On Fri, 10 Sep 2004 10:19:42 +0200, "Peter Koch Larsen"
<pk*****@mailme.dk> wrote:

"PKH" <no************@online.no> skrev i en meddelelse
news:FP******************@news4.e.nsc.no...

"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
>I am writing for game application. Performance is an issue.
>
> Any advise would be appreiciated.
>


I'm using the following approach in a game I'm working on. By inlining the
RequestClass functions it should be quite fast. (I posted this earlier in
another thread )


[snip]

You answered the question: is it possible to detect the object run time type
without using dynamic_cast. I see that it is. Could you also demonstrate
that it is faster than dynamic_cast? (In that case you should quote the
compiler and settings used)


dynamic_cast is notoriously slow on MSVC, since string comparisons are
used. Any reasonable home-grown solution will be faster than that.

Obviously, it is best to avoid the need for dynamic_cast full stop, or
at least limit to IO code where performance won't be an issue.

Tom
Jul 22 '05 #15
JKop wrote:
Jason Heyes posted:

"steve" <st***@mcube.com.tw> wrote in message
news:ch**********@netnews.hinet.net...
I am writing for game application. Performance is an
issue.
Any advise would be appreiciated.


Yea. Put the type into the base class.


No No No! This is clearly an instance in which one would
work with a pointer to a pointer to the *DERIVED CLASS*! To
put the type in the base clase is simply ludicrious!


I think what he means is that the base class could be defined with
either a member variable or virtual function (or both) that can be used
to indicate type, which can be overridden by derived classes.

#define CLASS_ID_BASE 0
#define CLASS_ID_DERIVED_A 1
#define CLASS_ID_DERIVED_B 2
/* ... */

class Base
{
public:
Base() : m_class_id(CLASS_ID_BASE) {}
Base(int a) : m_class_id(a) {}
virtual int GetClassID();
private:
int m_class_id;
};

int Base::GetClassID() {return m_class_id;}

class DerivedA : public Base
{
public:
DerivedA() : Base(CLASS_ID_DERIVED_A) {};
private:
int m_class_id;
};

class DerivedB : public Base
{
public:
DerivedB() : Base(CLASS_ID_DERIVED_B) {};
private:
int m_class_id;
};

and so on. With such a system, an application that has a Base *p can
call p->GetClassID() to obtain type info. The OP indicated that speed
was an issue; in this scenario the program can switch() on the value
returned from GetClassID(), or use it as an array index, etc.

--
Mike Smith
Jul 22 '05 #16

"Mike Smith" <mi*******************@acm.DOT.org> wrote in message
news:10*************@news.supernews.com...
#define CLASS_ID_BASE 0
#define CLASS_ID_DERIVED_A 1
#define CLASS_ID_DERIVED_B 2
/* ... */ Wow, do people still write code like that? How about a little type safety
and easier maintainability?

enum class_id_type {
CLASS_ID_BASE,
CLASS_ID_DERIVED_A,
CLASS_ID_DERIVED_B
};
and so on. With such a system, an application that has a Base *p can
call p->GetClassID() to obtain type info. The OP indicated that speed
was an issue; in this scenario the program can switch() on the value
returned from GetClassID(), or use it as an array index, etc.


You think switching on a class id is "better" or faster than just calling a
virtual member?

Jul 22 '05 #17
Xenos wrote:
"Mike Smith" <mi*******************@acm.DOT.org> wrote in message
news:10*************@news.supernews.com...
#define CLASS_ID_BASE 0
#define CLASS_ID_DERIVED_A 1
#define CLASS_ID_DERIVED_B 2
/* ... */


Wow, do people still write code like that? How about a little type safety
and easier maintainability?

enum class_id_type {
CLASS_ID_BASE,
CLASS_ID_DERIVED_A,
CLASS_ID_DERIVED_B
};


Yeah, yeah, OK. I was just looking to get something down that explained
the idea, and that's the first thing I thought of.
and so on. With such a system, an application that has a Base *p can
call p->GetClassID() to obtain type info. The OP indicated that speed
was an issue; in this scenario the program can switch() on the value
returned from GetClassID(), or use it as an array index, etc.


You think switching on a class id is "better" or faster than just calling a
virtual member?


I was responding to the question raised by the OP. Whether or not there
might be other ways to do what he "really" wants to achieve is a
different question, answering which would require telepathic abilities
on my part.

--
Mike Smith
Jul 22 '05 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Jamie Burns | last post by:
Hello, I just did a simple benchmark: for (xx=0;xx<100000;xx++) { rDerived* derived = dynamic_cast<rDerived*>(object); if (derived) derived->setValue(message.data.messageSetInt.value); } ...
8
by: Thomas Lorenz | last post by:
Hello, first, I didn't find any reference to my question through googling. dynamic_cast uses RTTI to determine if the cast expression is valid. Invalid casts of pointers give a '0'-result. As...
3
by: Ganesh | last post by:
On devx site, I saw following code. It says when a derived class is tried to cast to base type, it looks at the missing vtable and complains if the object is already deleted. I am of the opinion...
5
by: tthunder | last post by:
Hi @all, Perhaps some of you know my problem, but I had to start a new thread. The old one started to become very very confusing. Here clean code (which compiles well with my BCB 6.0 compiler)....
43
by: Mountain Bikn' Guy | last post by:
I have a situation where an app writes data of various types (primitives and objects) into a single dimensional array of objects. (This array eventually becomes a row in a data table, but that's...
5
by: mijobee | last post by:
Hello Everyone, I just wanted to check that I'm using dynamic_cast correctly. I have a hierarchy of objects using pure virtual classes and virtual inheritance to implement interfaces. I ran...
8
by: pietromas | last post by:
In the example below, why does the dynamic_cast fail (return NULL)? It should be able to cast between sibling classes ... #include <iostream> class A { public: virtual const int get()...
13
by: baltasarq | last post by:
Hi, there ! When I use dynamic_cast for a single object, I do something like: void foo(Base *base) { if ( dynamic_cast<Derived *>( base ) != NULL ) { ((Derived *) base)->do_something() } }
25
by: lovecreatesbea... | last post by:
Suppose I have the following three classes, GrandBase <-- Base <-- Child <-- GrandChild The following cast expression holds true only if pBase points object of type of ``Child'' or...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.