How to judge if two objects have the same type?

S

shuisheng

Dear All,

Assume I have a class named Obj.

class Obj
{ };

And a class named Shape which is derived from Obj.

class Shape: public Obj
{ };

And a class named Color which is also derived form Obj.

class Color: public Obj
{ };

I have two objects.

Obj *pA = new Shape or Color;
Obj *pB = new Shape or Color;

How can I know if they have the same type?

I appreciate your help.

Shuisheng
 
H

h.yuzhao

"shuisheng дµÀ£º
"
Dear All,

Assume I have a class named Obj.

class Obj
{ };

And a class named Shape which is derived from Obj.

class Shape: public Obj
{ };

And a class named Color which is also derived form Obj.

class Color: public Obj
{ };

I have two objects.

Obj *pA = new Shape or Color;
Obj *pB = new Shape or Color;

How can I know if they have the same type?

I appreciate your help.

Shuisheng

Did you consider about RTTI?
 
P

Puppet_Sock

shuisheng said:
Dear All,

Assume I have a class named Obj.

class Obj
{ };

And a class named Shape which is derived from Obj.

class Shape: public Obj
{ };

And a class named Color which is also derived form Obj.

class Color: public Obj
{ };

I have two objects.

Obj *pA = new Shape or Color;
Obj *pB = new Shape or Color;

How can I know if they have the same type?

Start with legal syntax.

C++ has type information built right into the syntax. What you
wrote there is not legal and is thus not a reasonable question.
It cannot be answered any more than one can answer any
non-sensical question.

You might ask something like (given your example classes)
if you had a function with prototype as such:

void myFunc(Obj *pObj);

then in the body of the function how could you tell what the
actual type of the object passed in was?

Or you could write something like this (psuedo code only):

if(complicated stuff that cannot always be predicted at compile time)
Obj *pA = new Shape;
else
Obj *pA = new Color;

How can you determine the type of the object pointed at by pA
after this runs?

There are two layers of answer: The first is "run time type info."
Look it up.

The second layer is, most of the time you shouldn't be asking
this question even in this situation. If you've got an inheritance,
the child class is supposed to be able to substitute for
the parent class. Look up Liskov substitution. A well written
C++ inheritance will work properly regardless of the type of
object that pA actually points to, provided it is public inheritance
from the type Obj. If you think you need this info, you should
be considering a rewrite of the classes involved so that you
don't need it.
Socks
 
S

Salt_Peter

shuisheng said:
Dear All,

Assume I have a class named Obj.

class Obj
{ };

And a class named Shape which is derived from Obj.

class Shape: public Obj
{ };

And a class named Color which is also derived form Obj.

class Color: public Obj
{ };

I have two objects.

Obj *pA = new Shape or Color;
Obj *pB = new Shape or Color;

How can I know if they have the same type?

I appreciate your help.

Shuisheng

First off, having everything derive from Obj is not a good idea. Shape
should be an abstract class here and color should reside in a distinct
inheritance hierarchy. Otherwise you will get headaches having to
manage what is what. Unlike Java, Obj base is not needed since C++ has
a much more resilient and powerful system called < templates >.

Lets face it, a C++ programmer should only need to detect type, as you
are attempting here, only in the rarest of occasions. Consider what
happens if you write a class that takes an Obj reference as a
parameter. How are you going to enforce what Obj is legally
accepteable? Using typeid? Thats downright wrong, unsafe and
complicated.
C++ needs not detect what type a given instance "belongs to". Thats
because an instance is an object. Its self aware. It already knows what
it can and cannot do. Thats the basis of OO design. making everything
an Obj defeats the purpose.

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <typeinfo>

class Shape { };
class Triangle : public Shape { };

// will only accept a Shape or derivative
void check_type(Shape& r_shape)
{
std::cout << "shape's type = ";
std::cout << typeid(r_shape).name();
std::cout << std::endl;
}

int main()
{
boost::shared_ptr< Shape > sp_shape(new Triangle);
check_type( *sp_shape );
}

/*
shape's type = Triangle
*/
 
B

BobR

Default User wrote in message ...
Please don't top-post. Your replies belong following or interspersed
with properly trimmed quotes. See the majority of other posts in the
newsgroup, or the group FAQ list:
<http://www.parashift.com/c++-faq-lite/how-to-post.html>

I was just thinking about a reply for such people:

" YOU IDIOT!! Do you realise you just screwed up a perfectly good thread!!
Now we'll have to reformat it and start over!! FAQ YOU!!"

"Please don't top-post" just isn't working since Google screwed up in a Gates
way.
 
G

Grizlyk

Salt_Peter said:
Unlike Java, Obj base is not needed since C++ has
a much more resilient and powerful system called templates<>.

I want to notice, that code, written with templates<>, is _compile time
template_ and can not replace (must just works together), of course,
any _runtime templates_.

In order to write class for _runtime template_ you must define a class
with the help of base class interface inheritance (public inheritance).
In order to use any function as _runtime template_, you must use for
all its runtime objects (variables) only pointers or references of its
public base class.

Of course, you must use inheritance _only_ for oo design necessity.
Using typeid? Thats downright wrong, unsafe and complicated.

One can do like this:
void foo(Obj& obj)
{
Shape* sh=dynamic_cast<Shape*>(&obj);
if(sh){ /* Shape-specific code */ }

Color* co=dynamic_cast<Color*>(&obj);
if(co){ /* Color-specific code */ }
}
C++ needs not detect what type a given instance "belongs to". Thats
because an instance is an object. Its self aware. It already knows what
it can and cannot do. Thats the basis of OO design. making everything
an Obj defeats the purpose.

One part of program can create object (and know _real_ object's class),
all other parts of program can use the created object (and know only
object's _base_ class), but some units of the others can use real
object's class again and are forced to cast base class reference to
derived class, and it can be done with dynamic_cast<>.

For instance, there is the design pattern named "decorator". In order
to get special interface of "decorated" object we are forced to cast to
derived class.

Also there is the design pattern using "pointer to indefinite class"
(for store objects and reorder them in storage (sorting etc)). In order
to get true interface of "stored" object we are forced to cast to
derived class.
 
N

Noah Roberts

Grizlyk said:
One can do like this:
void foo(Obj& obj)
{
Shape* sh=dynamic_cast<Shape*>(&obj);
if(sh){ /* Shape-specific code */ }

Color* co=dynamic_cast<Color*>(&obj);
if(co){ /* Color-specific code */ }
}

In my opinion most, if not all uses of dynamic_cast have bad design.
Namely they break LSP. The above is a perfect example.

but some units of the others can use real
object's class again and are forced to cast base class reference to
derived class, and it can be done with dynamic_cast<>.

They have no business accepting the base class interface then.
For instance, there is the design pattern named "decorator". In order
to get special interface of "decorated" object we are forced to cast to
derived class.

Huh? Decorator is a way to extend functionality through *composition*.
It implements the interface of the decorated object and becomes a
mediator, performing extra functionality as needed.
Also there is the design pattern using "pointer to indefinite class"
(for store objects and reorder them in storage (sorting etc)). In order
to get true interface of "stored" object we are forced to cast to
derived class.

There is an any object container in boost. I don't see a whole lot of
use in that object per se. I have used the constructs it uses to do
its job in some stuff I worked on wrt units and dimensional
analysis....to allow an object of any unit type to exist (when units
are separate static types) and I didn't use any of the casting or type
identification stuff. Besides stuff like that I don't see how it has
much use in well designed software....I could be wrong but that's how I
see it.
 
K

kwikius

shuisheng said:
Dear All,

Assume I have a class named Obj.

class Obj
{ };

And a class named Shape which is derived from Obj.

class Shape: public Obj
{ };

And a class named Color which is also derived form Obj.

class Color: public Obj
{ };

I have two objects.

Obj *pA = new Shape or Color;
Obj *pB = new Shape or Color;

How can I know if they have the same type?

I appreciate your help.

Techically you cant really know if two pointers are the same type, but
you can find if they have the interface you are looking for by dynamic
cast. If the cast succeeds then the type has the interface, if it fails
then the pointer will be empty:

#include <iostream>
#include <string>

struct base{
std::string name;
base(std::string const & name_in):name(name_in){}
virtual ~base(){} // some virtual function is required in the class
for dynamic cast to work
// a virtual destructor ensures that delete (if used) deletes the
actual object, not just the base
};

struct derived : base{
derived(std::string const & name):base(name){}
};

struct derived_derived : derived{
derived_derived(std::string const & name):derived(name){}
};


// examine a base pointer to see what interfaces it has
void f( base* pb)
{
if (!pb){
std::cout << "empty pointer!\n";
return;
}
derived * pd = dynamic_cast<derived*>(pb);
std::cout << pb->name << " is ";
if(!pd){
std::cout << "not ";
}
std::cout << "a derived\n";

derived_derived* pdd = dynamic_cast<derived_derived*>(pb);
std::cout << pb->name << " is ";
if(!pdd){
std::cout << "not ";
}
std::cout << "a derived_derived\n\n";
}

int main()
{
base b("base");
derived d("derived");
derived_derived dd("derived_derived");


base * pb = & b;
base * pd = & d;
base* pdd = & dd;

f(pb);
f(pd);
f(pdd);

}

/*
output:
base is not a derived
base is not a derived_derived

derived is a derived
derived is not a derived_derived

derived_derived is a derived
derived_derived is a derived_derived
*/
 
S

Salt_Peter

Grizlyk said:
I want to notice, that code, written with templates<>, is _compile time
template_ and can not replace (must just works together), of course,
any _runtime templates_.

Yes, thats right. templates<> is a system created to help a coder use
code.
Specially when the coder did *not* write the code.
Templates also lets a creator write rules for the benefit of the user.
In other words: the compiler can help you code if you do it with
templates.
Dynamic casts is a system that has your code thrown out the door by
your client.
Nobody has the time to read 10,000 lines of code to use your program.
Why don't you take up the issue with a professional Java programmer?
Because even the Java programmer will agree.
Dynamic casting is a nightmare for you - imagine the poor client.
 
T

t.lehmann

I think there're many solutions to implement type recognition
and it depends on the support state of your compiler, platform(s)
and its third party libraries.

- are you able/allowed to use RTTI?
- are you able/allowed to use Exceptions?

If you've problems as listed you can not use typeid nor dynamic_cast!
Proving a base class and an additional header with an enum of types you
can define in you base a
"virtual const eType typeId() const = 0;"

All classes derived from the base have to implement returning/adding
another enum value. Its's very simple solution!
(I don't say it's the best)
 
S

Salt_Peter

Grizlyk said:
I want to notice, that code, written with templates<>, is _compile time
template_ and can not replace (must just works together), of course,
any _runtime templates_.

In order to write class for _runtime template_ you must define a class
with the help of base class interface inheritance (public inheritance).
In order to use any function as _runtime template_, you must use for
all its runtime objects (variables) only pointers or references of its
public base class.

And how do you think the typeid is determined?

Yes, thats right. templates<> is a system created to help a coder use
code. Specially when the coder did *not* write the code.
Templates also lets a creator write rules for the benefit of the user.
In other words: the compiler can help you code if you do it with
templates.
Dynamic casts is a system that has your code thrown out the door by
your client.
Nobody has the time to read 10,000 lines of code to use your program.

Why don't you take up the issue with a professional Java programmer?
Because even the Java programmer will agree.
Dynamic casting is a nightmare for you - imagine the poor client.
Of course, you must use inheritance _only_ for oo design necessity.


One can do like this:
void foo(Obj& obj)
{
Shape* sh=dynamic_cast<Shape*>(&obj);
if(sh){ /* Shape-specific code */ }

Color* co=dynamic_cast<Color*>(&obj);
if(co){ /* Color-specific code */ }
}

really, one can do this instead:

struct Shape {
Color color;
Shape() : color() { } // whatever the default color is
Shape(const Color& col) : color(col) { }
};

Triangle : public Shape
{
Triangle() { }
Triangle(const Color& col) : Shape(col) { }
};

int main()
{
std::vector< Triangle > vt(1000000); // done - 1 million triangles
}

Thats one million Triangles, all initialized and valid, default color
and ready for action.
Care to try to reproduce that with your code? Oh yes, and i've got 100
more shapes for you and 1000 different colours. Very easy for a
template. You need what: 10,000 lines of code? 1 million lines of code?
How much?

Here, now i need 1 million more triangles and they must all be Color
black:

Color black(...); // where ... is whatever color black requires
std::vector< Triangle > blktriangles(1000000, black); // done

How many more lines of code do *you* need now? Note: i didn't change a
single line of the above classes to make that work. Beats the hell out
of using a dynamic cast, doesn't it?
 
D

Default User

BobR said:
Default User wrote in message ...

I was just thinking about a reply for such people:

" YOU IDIOT!! Do you realise you just screwed up a perfectly good
thread!! Now we'll have to reformat it and start over!! FAQ YOU!!"

"Please don't top-post" just isn't working since Google screwed up in
a Gates way.

I've had reasonably good results with the above message, and a similar
one on clc. Whenever I post just this information, I add "- TPA" to the
subject. That way regulars can filter the messages if they choose.



Brian
 
G

Grizlyk

They have no business accepting the base class interface then.

There are cases of program design necessity. For instance, it can be
pair of classes developed together: "creater"-"user". They improve
integrated base functionality of existing program, so no one unit of
existing (and may be compiled) program do not know about new derived
classes and "creater"-"user" must communicate "over" pointer to base
class.
Huh? Decorator is a way to extend functionality through *composition*.
It implements the interface of the decorated object and becomes a
mediator, performing extra functionality as needed.

It is true, the "implementaion" of the pattern goal can be done by
"composition of the decorated object", but "composition" can be not
enough.

You have written "implements the interface of the decorated object".
Not only "implement", it is better to say "inherit the interface of the
decorated object or its base class". It is good if you can limit
decorator interface by interface of its decorated object.

But sometimes it is really imposible - we need to adjust own decorator
properties (they have no sense and they do not exist for decorated
object) _after_ decorator have created, so we need extra "decorator"
interface and a way to get the interface from pointer to the class of
"decorated" object.
There is an any object container in boost. I don't see a whole lot of
use in that object per se. I have used the constructs it uses to do
its job in some stuff I worked on wrt units and dimensional
analysis.... to allow an object of any unit type to exist (when units
are separate static types) and I didn't use any of the casting or type
identification stuff.

"object per se"? "wrt"? What use what? Sorry, I do no know english well
and do not understand what do you speak about :)
Besides stuff like that I don't see how it has
much use in well designed software....

I do not understand the goal of the special "stuff", you have spoken
about, but i can describe the design pattern "pointer to indefinite
class". In order to describe any design pattern, you need to define at
least three things:
1. context to apply the pattern
2. the goal of the pattern
3. the way of the pattern implementation

For design pattern "pointer to indefinite class":
1. not shared ot local-shared libraris of program with many quantity
(for example 100)
of different types and classes, which must be placed in lists, arrays
etc

2. decrease code size :) (do not want to create 100 equal copies of
lists, arrays etc) by making single class for each type of container
(list, array etc) to keep "object of indefinite class", by allowing
single copy for each type of "algorithm" methods, based on "interface
of indefinite class".

3. i think it is out of "comp.lang.c++" topic and "How to judge if two
objects have the same type" too, but say some words:
a)"interface of indefinite class" depends from concrete program (so we
get "local-shared" pattern context), for example, the easy interface
are virtuals: create/copy/clone constructors and destructor.

b)we inherite all "containerable" types of the program from
program-global base class "indefinite class"

c)type check and type-dependent interdace for "remove/insert_correct
type_object" we make with template<> (template<> inherit
"concrete_container" from "container_of_indefinit_class" ), so we can't
get "runtime bad_cast" and each template<> copy of code do chiefly only
dynamic_cast (so can not be optimized more).
 
G

Grizlyk

Salt_Peter said:
And how do you think the typeid is determined?

I think nothing about typeid and its implementaion :) I want only to
notice said:
Templates also lets a creator write rules for the benefit of the user.
In other words: the compiler can help you code if you do it with
templates.

I think "can help you code" is very magical and vague definition. Any
improper use of teplate<> will give your in better case many
unnecessary copies of code. You can or must use teplate<> at least:

1. due to C++ strict type control
There are object-oriented languges, which no need template<> for type
conversion, due to runtime type identification and message posting. For
C++ you can not declare interface of base class, if class members of
the interface have return's or parameter's type of unknown or derived
class. Template<> for type conversion must be as easy, as you can do,
so ideal case is only casting to proper class. Template<> for type
conversion will be instanced for each class as class's own copy of
code.

2. for "general programming"
That is good, to declare any type ("general goal") of code templates
with the help of template<>, but you must not instance each "general
goal" template<> directly "as is". It is much better ro prefer _runtime
remplate_, so you must do instance only for one or two copyies of
Dynamic casts is a system that has your code thrown out the door by
your client.
Nobody has the time to read 10,000 lines of code to use your program.
Dynamic casting is a nightmare for you - imagine the poor client.

Dynamic casting is quite low-level feature of C++, it is absolutely
necessary for interface implementaion but no one force anybody do
dynamic casting in each line of you program. In good system of classes
dynamic casting can be hidden and incapsulated by interface of each
class.
really, one can do this instead:
You are right, but the man asked not his classes desing way, but
runtime class type identyfication (Is it maybe FAQ question? I do not
know). No one can guess his real class hierarhy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top