Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > rtti

Reply
 
 
Chameleon
Guest
Posts: n/a
 
      05-02-2011
Hi!
I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
base class `Relation`.
I want to put all of these in a `vector<Relation>` but they have
different size, so, I create a `union AnyRelation` and I put all of
derived classes inside this union, and the vector become
`vector<AnyRelation>`.
When I want to check what type the derived class is, I use `typeid`.

Is there a better approach, or I am going right?

Another try, is to put every derived class in its own vector:
vector<Azimuth>
vector<Angle>
vector<Distance>
and so on.
and in a `vector<Relation>` I can use references to real objects.
With this approach I can avoid the `typeid` because I can check if
pointer of derived class object belongs to a specific `vector`.


And a final question:
Its better to create my own rtti, or to use build-in? (for speed)
My own rtti:
------------
class A {
A() : rtti(0) {}
int rtti;
int getRTTI() { return rtti; }
bool isB() { return rtti == 1; }
virtual ~A() {}
};
class B : public A {
B() { rtti = 1; }
};
 
Reply With Quote
 
 
 
 
Pavel
Guest
Posts: n/a
 
      05-02-2011
Chameleon wrote:
> Hi!
> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> base class `Relation`.
> I want to put all of these in a `vector<Relation>` but they have
> different size, so, I create a `union AnyRelation` and I put all of
> derived classes inside this union, and the vector become
> `vector<AnyRelation>`.
> When I want to check what type the derived class is, I use `typeid`.
>
> Is there a better approach, or I am going right?

Mostly theoretically, I can see a situation where the derived classes have
different alignment from the derived class. Thus, even if the hierarchy only
uses single inheritance, you would have to know the type before accessing the
object in the union (and as you do it to learn the type, you have a
chicken-and-egg issue)..
>
> Another try, is to put every derived class in its own vector:
> vector<Azimuth>
> vector<Angle>
> vector<Distance>
> and so on.
> and in a `vector<Relation>` I can use references to real objects.
> With this approach I can avoid the `typeid` because I can check if
> pointer of derived class object belongs to a specific `vector`.

This will work.
>
>
> And a final question:
> Its better to create my own rtti, or to use build-in? (for speed)
> My own rtti:
> ------------
> class A {
> A() : rtti(0) {}
> int rtti;
> int getRTTI() { return rtti; }
> bool isB() { return rtti == 1; }
> virtual ~A() {}
> };
> class B : public A {
> B() { rtti = 1; }
> };

If you have virtual destructor anyway, you can save an int by defining a virtual
instead
virtual int getRTTI() const { return <type>; }

Using built-in RTTI would work with less effort (although maybe with same
performance).

Please note I do not comment on your design because I do not know its purpose.
Often, however, the designs directly checking the types are suspects. It's
*usually* better make class objects do things by calling virtual functions than
checking their types and do things with them. Again, not knowing your goal, I
can't say with confidence this will work better in your case but you might want
to give it a look.

HTH,
-Pavel


 
Reply With Quote
 
 
 
 
Marcel Müller
Guest
Posts: n/a
 
      05-02-2011
Chameleon wrote:
> Hi!
> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> base class `Relation`.
> I want to put all of these in a `vector<Relation>` but they have
> different size, so, I create a `union AnyRelation` and I put all of
> derived classes inside this union, and the vector become
> `vector<AnyRelation>`.
> When I want to check what type the derived class is, I use `typeid`.


typeid won't help you, as you must not access any member of a union
except for the one you put into the union. So typeid would enable you to
store a fixed set of types in a predefined union. (Anything else would
be an exception.) But how do you extract the classes from the union
without accessing the wrong one?

> Is there a better approach, or I am going right?


Absolutely. If you really need polymorphic members in a vector, you
won't come around using pointer or smart pointers and separate allocations.

If you are restricted to only a few types, have a look at
boost::variant. It addresses almost exactly what you want to do.


> Another try, is to put every derived class in its own vector:
> vector<Azimuth>
> vector<Angle>
> vector<Distance>
> and so on.
> and in a `vector<Relation>` I can use references to real objects.
> With this approach I can avoid the `typeid` because I can check if
> pointer of derived class object belongs to a specific `vector`.


I would prefer to use a vector<Relation> that owns it's objects in some
way (shared or not).


> And a final question:
> Its better to create my own rtti, or to use build-in? (for speed)
> My own rtti:
> ------------
> class A {
> A() : rtti(0) {}
> int rtti;
> int getRTTI() { return rtti; }
> bool isB() { return rtti == 1; }
> virtual ~A() {}
> };
> class B : public A {
> B() { rtti = 1; }
> };


This will primarily create a memory overhead, since unlike you almost no
compiler stores any RTTI per instance. As long as you use RTTI only for
equality comparison it is most likely faster than anything you could
write, because effectively only slots of the vtable are compared. There
is no virtual function call and no linear memory overhead.


Marcel
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      05-02-2011
On May 2, 5:03*am, Chameleon <(E-Mail Removed)> wrote:
> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> base class `Relation`.
> I want to put all of these in a `vector<Relation>` but they have
> different size, so, I create a `union AnyRelation` and I put all of
> derived classes inside this union, and the vector become
> `vector<AnyRelation>`.
>
> When I want to check what type the derived class is, I use `typeid`.


It is asking for difficulties. C++0x changed the union a bit but i
still dislike it.

> Is there a better approach, or I am going right?


I suspect your way it won't work.

1) More common alternatives:

vector<boost::shared_ptr<Relation> >
vector<tr1::unique_ptr<Relation> >

2) Just

vector<Relation*>

works for those who do not want dependency on boost or C++0x
extensions. It is more error-prone when dealing with raw pointers so
enwrap it into something.

3) You can remove the exposed polymorphism by using pimpl idiom so
Relation becomes envelope class and `Angle`, `Azimuth`, `Distance`,
`Height` are its hidden internal variants of implementation. Then
vector<Relation> works fine.

> Another try, is to put every derived class in its own vector:
> vector<Azimuth>
> vector<Angle>
> vector<Distance>
> and so on.


That loses polymorphism over common interface Relation and you will
have several containers to manage.

> and in a `vector<Relation>` I can use references to real objects.


References can not be stored in vector. Also you should avoid storing
iterators or references or pointers to elements of vector. These get
invalid if you insert, erase or push_back into vector.

> With this approach I can avoid the `typeid` because I can check if
> pointer of derived class object belongs to a specific `vector`.
>
> And a final question:
> Its better to create my own rtti, or to use build-in? (for speed)
> My own rtti:
> ------------
> class A {
> * * * * A() : rtti(0) {}
> * * * * int rtti;
> * * * * int getRTTI() { return rtti; }
> * * * * bool isB() { return rtti == 1; }
> * * * * virtual ~A() {}};
>
> class B : public A {
> * * * * B() { rtti = 1; }
> };


Nah ... avoid magic numbers and avoid writing things yourself that are
present in language. The people writing compilers are way over average
skilled and their user base is large so their defects will be most
likely discovered and fixed before your software reaches your end
users.

Use built-in RTTI when you need to. Beware that you should avoid
directly using RTTI as lot you can. Using RTTI too lot indicates weak
design. dynamic_cast can be useful for acquiring (or checking
presence of) other interfaces when having an interface pointer. For
typeid there are too few good use cases besides debugging and
troubleshooting.
 
Reply With Quote
 
Chameleon
Guest
Posts: n/a
 
      05-02-2011
Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib *γραψε:
> On May 2, 5:03 am, Chameleon<(E-Mail Removed)> wrote:
>> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
>> base class `Relation`.
>> I want to put all of these in a `vector<Relation>` but they have
>> different size, so, I create a `union AnyRelation` and I put all of
>> derived classes inside this union, and the vector become
>> `vector<AnyRelation>`.
>>
>> When I want to check what type the derived class is, I use `typeid`.

>
> It is asking for difficulties. C++0x changed the union a bit but i
> still dislike it.
>
>> Is there a better approach, or I am going right?

>
> I suspect your way it won't work.
>
> 1) More common alternatives:
>
> vector<boost::shared_ptr<Relation> >
> vector<tr1::unique_ptr<Relation> >
>
> 2) Just
>
> vector<Relation*>
>


Create large number of small individual objects in heap is overhead.
It sounds like Java to me.

> works for those who do not want dependency on boost or C++0x
> extensions. It is more error-prone when dealing with raw pointers so
> enwrap it into something.
>
> 3) You can remove the exposed polymorphism by using pimpl idiom so
> Relation becomes envelope class and `Angle`, `Azimuth`, `Distance`,
> `Height` are its hidden internal variants of implementation. Then
> vector<Relation> works fine.


My approach a little bit similar:
Every of 5 derived classes in its own vector. (Instead of every single
object in a new block in heap)
A big vector with envelope class for derived classes implementing the
operator* to access base class which has the complete functionality.
Envelope class has the type of derivative class and the index in its vector.

The problem is that I cannot use only one derived class to do something,
but different derived classes together. E.g. Distance and Angle (to
describe a new point) or angle and angle, or distance and distance and
clockwise.

And after I will use all of these as springs linear (Distance, Height)
or angular (Angle, Azimuth) to minimize the error.

>> Another try, is to put every derived class in its own vector:
>> vector<Azimuth>
>> vector<Angle>
>> vector<Distance>
>> and so on.

>
> That loses polymorphism over common interface Relation and you will
> have several containers to manage.
>
>> and in a `vector<Relation>` I can use references to real objects.

>
> References can not be stored in vector. Also you should avoid storing
> iterators or references or pointers to elements of vector. These get
> invalid if you insert, erase or push_back into vector.

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-02-2011
On May 2, 3:03 am, Chameleon <(E-Mail Removed)> wrote:

> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> base class `Relation`.
> I want to put all of these in a `vector<Relation>` but they have
> different size, so, I create a `union AnyRelation` and I put all of
> derived classes inside this union, and the vector become
> `vector<AnyRelation>`.
> When I want to check what type the derived class is, I use `typeid`.


> Is there a better approach, or I am going right?


Well, there's one major problem with your approach. It isn't
legal C++, and won't compile. At least assuming that Relation
has any virtual functions (and it should, otherwise, there's no
point in the derivation). What you can do is use something like
boost::variant, or even boost::any, but usually (not always),
the need for such a solution is indicative of a design error.

> Another try, is to put every derived class in its own vector:
> vector<Azimuth>
> vector<Angle>
> vector<Distance>
> and so on.
> and in a `vector<Relation>` I can use references to real objects.
> With this approach I can avoid the `typeid` because I can check if
> pointer of derived class object belongs to a specific `vector`.


The real question is what you are doing with the typeid to begin
with. You've not described the problem in enough detail, or
rather at a high enough level, for us to make any concrete
suggestions, but in most cases, if Azimuth implements Relation,
client code should be able to deal with just Relation, without
knowing that this particular Relation is an Azimuth. (Again,
there are exceptions, but they are few and far between. And
generally only concern a single subset of the derived classes.)

> And a final question:
> Its better to create my own rtti, or to use build-in? (for speed)
> My own rtti:
> ------------
> class A {
> A() : rtti(0) {}
> int rtti;
> int getRTTI() { return rtti; }
> bool isB() { return rtti == 1; }
> virtual ~A() {}};


> class B : public A {
> B() { rtti = 1; }
> };


In general, it's better to only use virtual functions. If some
of the derived classes have to implement an extended interface,
then I'd probably go with dynamic_cast until the profiler showed
it to be a problem. If it is a performance problem, and the
design really does require such, then you can consider something
like:

class Base
{
// ...
virtual Extended* getExtended() { return NULL; }
// ...
};

class Extended : public Base
{
virtual Extended* getExtended() { return this; }
// ...
};

Those classes which implement the extended interface derived
from Extended; those which don't, don't.

And for better or for worse, once polymorphism enters into the
scene, you're going to have to deal with pointers and dynamic
allocation. Since, based on the names, I'd guess that these are
really "value" type objects (which you'ld copy, and never
allocate dynamically if the polymorphism wasn't involved), and
they probably don't contain pointers to other objects (so you
can't get cycles), you can consider using some sort of reference
counting pointer; boost::shared_ptr, or better yet, some sort of
invasive pointer (and have Relation contain the counter);
alternatively, if you make all of the constructors private,
use factory methods which return the smart pointers, and none of
the types ever call any function which might take a pointer to
the object itself, you can probably use boost::shared_ptr
without too many problems.

--
James Kanze
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-02-2011
On May 2, 9:00 pm, Chameleon <(E-Mail Removed)> wrote:
> Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib *γραψε:
> > On May 2, 5:03 am, Chameleon<(E-Mail Removed)> wrote:
> >> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> >> base class `Relation`.
> >> I want to put all of these in a `vector<Relation>` but they have
> >> different size, so, I create a `union AnyRelation` and I put all of
> >> derived classes inside this union, and the vector become
> >> `vector<AnyRelation>`.


> >> When I want to check what type the derived class is, I use `typeid`.


> > It is asking for difficulties. C++0x changed the union a bit but i
> > still dislike it.


> >> Is there a better approach, or I am going right?


> > I suspect your way it won't work.


> > 1) More common alternatives:


> > vector<boost::shared_ptr<Relation> >
> > vector<tr1::unique_ptr<Relation> >


> > 2) Just


> > vector<Relation*>


> Create large number of small individual objects in heap is overhead.
> It sounds like Java to me.


The reason Java works like this is that it more or less assumes
(or almost requires) that every object is polymorphic. From
what you've described, that's the case you're in. As soon as
polymorphism comes into play, C++ starts allocating dynamically
as well.

> > works for those who do not want dependency on boost or C++0x
> > extensions. It is more error-prone when dealing with raw
> > pointers so enwrap it into something.


There are very few things as error prone as boost::shared_ptr.
At least for the sort of things one usually allocates
dynamically; his case may be the exception (but he's not told us
enough about the derived types to be sure).

> > 3) You can remove the exposed polymorphism by using pimpl idiom so
> > Relation becomes envelope class and `Angle`, `Azimuth`, `Distance`,
> > `Height` are its hidden internal variants of implementation. Then
> > vector<Relation> works fine.


But he still ends up with a lot of small allocations.

From the names, I suspect that a single class, with a
discriminator indicating how to interpret the contents, and
perhaps a union with the actual data, might be appropriate.
Might be---one really can't say without knowing more about the
applications.

> My approach a little bit similar:
> Every of 5 derived classes in its own vector. (Instead of every single
> object in a new block in heap)
> A big vector with envelope class for derived classes implementing the
> operator* to access base class which has the complete functionality.
> Envelope class has the type of derivative class and the index in its vector.


> The problem is that I cannot use only one derived class to do something,
> but different derived classes together. E.g. Distance and Angle (to
> describe a new point) or angle and angle, or distance and distance and
> clockwise.


> And after I will use all of these as springs linear (Distance, Height)
> or angular (Angle, Azimuth) to minimize the error.


I'm not sure I've understood what you're trying to do, so this
might be complete rubish, but it vaguely sounds like you're
trying to maintain a position (relative or absolute?) in several
different formats. The usual solution here is to unify the
format inside the class, and add manupulators along the lines of
changeAzimut, etc.

--
James Kanze
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      05-03-2011
Chameleon <(E-Mail Removed)> wrote:
> Create large number of small individual objects in heap is overhead.


Sometimes you simply don't have a choice. Dynamic polymorphism usually
means that you must allocate on the heap. Depending on how often and
how many you need to do it, the overhead may well be inconsequential.
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      05-03-2011
On May 3, 2:09*am, James Kanze <(E-Mail Removed)> wrote:
> On May 2, 9:00 pm, Chameleon <(E-Mail Removed)> wrote:
> > Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib *γραψε:
> > > On May 2, 5:03 am, Chameleon<(E-Mail Removed)> *wrote:
> > >> I have derived classes `Angle`, `Azimuth`, `Distance`, `Height` from
> > >> base class `Relation`.
> > >> I want to put all of these in a `vector<Relation>` but they have
> > >> different size, so, I create a `union AnyRelation` and I put all of
> > >> derived classes inside this union, and the vector become
> > >> `vector<AnyRelation>`.
> > >> When I want to check what type the derived class is, I use `typeid`.
> > > It is asking for difficulties. C++0x changed the union a bit but i
> > > still dislike it.
> > >> Is there a better approach, or I am going right?
> > > I suspect your way it won't work.
> > > 1) More common alternatives:
> > > * vector<boost::shared_ptr<Relation> *>
> > > * vector<tr1::unique_ptr<Relation> *>
> > > 2) Just
> > > * vector<Relation*>

> > Create large number of small individual objects in heap is overhead.
> > It sounds like Java to me.

>
> The reason Java works like this is that it more or less assumes
> (or almost requires) that every object is polymorphic. *From
> what you've described, that's the case you're in. *As soon as
> polymorphism comes into play, C++ starts allocating dynamically
> as well.


The whole concern about small allocations sounds a bit premature for
me. Marcel Müller suggested something like:

vector<boost::variant<Angle, Azimuth, Distance, Height>

That will not allocate lot of small objects. My experience is that
boost::variant does not also fit for polymorphic classes (but is
certainly better than union).

> > > works for those who do not want dependency on boost or C++0x
> > > extensions. It is more error-prone when *dealing with raw
> > > pointers so enwrap it into something.

>
> There are very few things as error prone as boost::shared_ptr.
> At least for the sort of things one usually allocates
> dynamically; his case may be the exception (but he's not told us
> enough about the derived types to be sure).


I am not sure why shared_ptr is error prone. It is a tool like any
other tool and it is *wrong* to use it at numerous places. Who knows
how it is for OP's problem. Thats why i gave several options. If it
fits the design then i would use shared_ptr instead of raw pointer.

> > > 3) You can remove the exposed polymorphism by using pimpl idiom so
> > > Relation becomes envelope class and *`Angle`, `Azimuth`, `Distance`,
> > > `Height` are its hidden internal variants of implementation. Then
> > > vector<Relation> *works fine.

>
> But he still ends up with a lot of small allocations.


If it becomes concern then OP may use boost:ool for fast dynamic
allocations (with pimpl it works great) also he can use other nice
optimizations with pimpl (like lazy copy-on-write).

> From the names, I suspect that a single class, with a
> discriminator indicating how to interpret the contents, and
> perhaps a union with the actual data, might be appropriate.
> Might be---one really can't say without knowing more about the
> applications.


Yes, that is also possibility. It can however result with hard-to-
maintain C-style switch-case polymorphism in unskilled hands. I would
first try to move real polymorphism to implementation detail.
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      05-03-2011
On May 2, 11:00*pm, Chameleon <(E-Mail Removed)> wrote:
> Στις 02 Μαϊ 2011 14:05, ο/η Öö Tiib *γραψε:
>
> > 3) You can remove the exposed polymorphism by using pimpl idiom so
> > Relation becomes envelope class and *`Angle`, `Azimuth`, `Distance`,
> > `Height` are its hidden internal variants of implementation. Then
> > vector<Relation> *works fine.

>
> My approach a little bit similar:
> Every of 5 derived classes in its own vector. (Instead of every single
> object in a new block in heap)
> A big vector with envelope class for derived classes implementing the
> operator* to access base class which has the complete functionality.
> Envelope class has the type of derivative class and the index in its vector.


The "own vectors" in your design sound like custom memory management.
If so then use things designed for memory management like boost:ool.

> The problem is that I cannot use only one derived class to do something,
> but different derived classes together. E.g. Distance and Angle (to
> describe a new point) or angle and angle, or distance and distance and
> clockwise.
>
> And after I will use all of these as springs linear (Distance, Height)
> or angular (Angle, Azimuth) to minimize the error.


It feels that the Distance, Height, Angle and Azimuth are not
descendants of generic Relation (that "does something") but its
possible components. So actually you should have LinearRelation and
AngularRelation derived from Relation?
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[RTTI] cast base class pointer to <templated> derived class pointer tirath C++ 3 10-12-2003 01:44 PM
RTTI versus a base class enum to represent type BillyO C++ 2 09-30-2003 10:21 PM
About RTTI Steven Lien C++ 4 08-19-2003 06:03 PM
Re: RTTI John Harrison C++ 2 07-14-2003 02:36 PM
Re: RTTI Alf P. Steinbach C++ 0 07-14-2003 08:18 AM



Advertisments