Can I avoid rewriting this function in a subclass?

S

Steve Edwards

Hi,

I'm trying to find a simple way to identify which of a heirachy of
classes a particular class is:

class Agent
{
public:
enum { class_ID = 'Agnt' };
Agent();
virtual ~Agent(){};
virtual string ClassID();

protected:
};

//----------------------------
string Agent::ClassID()
{
char id[4] = {(char)(class_ID>>24), (char)(class_ID>>16),
(char)(class_ID>>8), (char)class_ID };
string strID(id, 4);
return strID;
}
//----------------------------

This works, and returns as a string the class_ID "Agnt"

But then I declare subclasses, such as:

class SubAgent : public Agent
{
public:
enum { class_ID = 'SubA' };
(SubAgent);
virtual ~ SubAgent(){};

protected:
};


Now if I examine SubAgent's class_ID in the debugger I can see that it
has the correct id = 'SubA'. But if I try to retreive it via ClassID(),
I get the Super Class's id of "Agnt".

Is the only solution to re-declare and cut'n'paste a copy of ClassID()
for each of the many sub-classes I have?

Or is there just a better way to do this altogether?


Thanks

Steve
 
O

Owen Jacobson

Hi,

I'm trying to find a simple way to identify which of a heirachy of
classes a particular class is:

Use the built-in RTTI operations (dynamic_cast<T> and friends), or, better
yet, scrap the design and rebuild it. Needing to know which subclass
something is is almost invariably a sign that you shouldn't be using
inheritance at all.

What's the real problem you're solving?
 
S

Steve555

Owen said:
Use the built-in RTTI operations (dynamic_cast<T> and friends), or, better
yet, scrap the design and rebuild it. Needing to know which subclass
something is is almost invariably a sign that you shouldn't be using
inheritance at all.

What's the real problem you're solving?

It's a natural-language-understanding app, and the classes represent
real world heirarchical objects i.e. poodle isa dog isa mammal isa
animal isa living-thing etc.
Knowing which subclass something is is the whole point, so that
semantic inferences can be made; I want to be able to infer all the
properties of Living_Thing , but at the same time know whether I can
call Bark() or Talk().

Thanks

Steve
 
I

Ivan Vecerina

: I'm trying to find a simple way to identify which of a heirachy of
: classes a particular class is:
:
: class Agent
: {
: public:
: enum { class_ID = 'Agnt' };
: Agent();
: virtual ~Agent(){};
: virtual string ClassID();
:
: protected:
: };
:
: //----------------------------
: string Agent::ClassID()
: {
: char id[4] = {(char)(class_ID>>24), (char)(class_ID>>16),
: (char)(class_ID>>8), (char)class_ID };
: string strID(id, 4);
: return strID;
: }
: //----------------------------
:
: This works, and returns as a string the class_ID "Agnt"
:
: But then I declare subclasses, such as:
:
: class SubAgent : public Agent
: {
: public:
: enum { class_ID = 'SubA' };
: (SubAgent);
: virtual ~ SubAgent(){};
:
: protected:
: };
:
:
: Now if I examine SubAgent's class_ID in the debugger I can see that it
: has the correct id = 'SubA'. But if I try to retreive it via ClassID(),
: I get the Super Class's id of "Agnt".
:
: Is the only solution to re-declare and cut'n'paste a copy of ClassID()
: for each of the many sub-classes I have?

For the accessed value of class_ID to be class-specific,
you need a virtual function.
So you could write:
class Agent
{
public:
string ClassID();
private:
virtual unsigned long class_ID() { return 'Agnt'; }
};

string Agent::ClassID()
{
unsigned long v = this->class_ID();
char id[4] = {(char)(v>>24), (char)(v>>16), (char)(v>>8), (char)v };
return string(id, 4);
}

// each subclass overrides the 'class_ID()' function.

: Or is there just a better way to do this altogether?

Why have 'class_ID' both as a string and as a numeric value?
You should be able to drop-out either representation
from the class itself.

+from your previous reply:
: It's a natural-language-understanding app, and the classes represent
: real world hierarchical objects i.e. poodle isa dog isa mammal isa
: animal isa living-thing etc.
dynamic_cast & typeid allow you to find this out at run-time.

: Knowing which subclass something is is the whole point, so that
: semantic inferences can be made; I want to be able to infer all the
: properties of Living_Thing , but at the same time know whether I can
: call Bark() or Talk().
Support for specific functions can also be determined by (multiply)
deriving from interface classes.

Example:

#include <iostream>

using namespace std;

struct IBark {
virtual void bark()=0;
};

class Animal { public: virtual ~Animal()=0; };
inline Animal::~Animal() {}
class Mammal : public Animal { };
class Dog : public Mammal, public IBark {
public: virtual void bark() { cout<<"woof!"<<endl; }
};

void foo( Animal& a )
{
cout << "foo has received a "<<typeid(a).name()<<endl;
Mammal* isMammal = dynamic_cast<Mammal*>(&a); // NULL if not a mammal
if( isMammal!=NULL ) cout<<" It is a Mammal !"<<endl;
Dog* isDog = dynamic_cast<Dog*>(&a); // NULL if not a dog
if( isDog!=NULL ) isDog->bark();
IBark* canBark = dynamic_cast<IBark*>(&a);
if( isDog==NULL && canBark!=NULL ) //barking plant?
canBark->bark();
}

int main()
{
Mammal a;
foo(a);
Dog d;
foo(d);
}



-Ivan
 
S

Steve555

Ivan said:
: I'm trying to find a simple way to identify which of a heirachy of
: classes a particular class is:
:
: class Agent
: {
: public:
: enum { class_ID = 'Agnt' };
: Agent();
: virtual ~Agent(){};
: virtual string ClassID();
:
: protected:
: };
:
: //----------------------------
: string Agent::ClassID()
: {
: char id[4] = {(char)(class_ID>>24), (char)(class_ID>>16),
: (char)(class_ID>>8), (char)class_ID };
: string strID(id, 4);
: return strID;
: }
: //----------------------------
:
: This works, and returns as a string the class_ID "Agnt"
:
: But then I declare subclasses, such as:
:
: class SubAgent : public Agent
: {
: public:
: enum { class_ID = 'SubA' };
: (SubAgent);
: virtual ~ SubAgent(){};
:
: protected:
: };
:
:
: Now if I examine SubAgent's class_ID in the debugger I can see that it
: has the correct id = 'SubA'. But if I try to retreive it via ClassID(),
: I get the Super Class's id of "Agnt".
:
: Is the only solution to re-declare and cut'n'paste a copy of ClassID()
: for each of the many sub-classes I have?

For the accessed value of class_ID to be class-specific,
you need a virtual function.
So you could write:
class Agent
{
public:
string ClassID();
private:
virtual unsigned long class_ID() { return 'Agnt'; }
};

string Agent::ClassID()
{
unsigned long v = this->class_ID();
char id[4] = {(char)(v>>24), (char)(v>>16), (char)(v>>8), (char)v };
return string(id, 4);
}

// each subclass overrides the 'class_ID()' function.

: Or is there just a better way to do this altogether?

Why have 'class_ID' both as a string and as a numeric value?
You should be able to drop-out either representation
from the class itself.

+from your previous reply:
: It's a natural-language-understanding app, and the classes represent
: real world hierarchical objects i.e. poodle isa dog isa mammal isa
: animal isa living-thing etc.
dynamic_cast & typeid allow you to find this out at run-time.

: Knowing which subclass something is is the whole point, so that
: semantic inferences can be made; I want to be able to infer all the
: properties of Living_Thing , but at the same time know whether I can
: call Bark() or Talk().
Support for specific functions can also be determined by (multiply)
deriving from interface classes.

Example:

#include <iostream>

using namespace std;

struct IBark {
virtual void bark()=0;
};

class Animal { public: virtual ~Animal()=0; };
inline Animal::~Animal() {}
class Mammal : public Animal { };
class Dog : public Mammal, public IBark {
public: virtual void bark() { cout<<"woof!"<<endl; }
};

void foo( Animal& a )
{
cout << "foo has received a "<<typeid(a).name()<<endl;
Mammal* isMammal = dynamic_cast<Mammal*>(&a); // NULL if not a mammal
if( isMammal!=NULL ) cout<<" It is a Mammal !"<<endl;
Dog* isDog = dynamic_cast<Dog*>(&a); // NULL if not a dog
if( isDog!=NULL ) isDog->bark();
IBark* canBark = dynamic_cast<IBark*>(&a);
if( isDog==NULL && canBark!=NULL ) //barking plant?
canBark->bark();
}

int main()
{
Mammal a;
foo(a);
Dog d;
foo(d);
}

Thanks Ivan, that covers all that I need to do. A quick Googling seems
to show that typeid might be faster than dynamic_cast, as it's a fixed
execution time, as opposed to being dependent on how deep the class
heirarch is (?). I'll use both methods you showed and see if there's
any perceptible performance difference.
 
R

Richard Herring

It's a natural-language-understanding app, and the classes represent
real world heirarchical objects i.e. poodle isa dog isa mammal isa
animal isa living-thing etc.
Knowing which subclass something is is the whole point, so that
semantic inferences can be made; I want to be able to infer all the
properties of Living_Thing , but at the same time know whether I can
call Bark() or Talk().
The obvious[*] solution to _that_ is to have functions such as:

virtual bool CanBark() const;

etc.

[*] Not necessarily a good one ;-(
 
J

Jeff Flinn

Richard said:
....
It's a natural-language-understanding app, and the classes represent
real world heirarchical objects i.e. poodle isa dog isa mammal isa
animal isa living-thing etc.
Knowing which subclass something is is the whole point, so that
semantic inferences can be made; I want to be able to infer all the
properties of Living_Thing , but at the same time know whether I can
call Bark() or Talk().
The obvious[*] solution to _that_ is to have functions such as:

virtual bool CanBark() const;

etc.

[*] Not necessarily a good one ;-(

Perhaps further abstraction of the operation is required:

virtual void Communicate()const;

Jeff
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,121
Latest member
LowellMcGu
Top