Can I avoid rewriting this function in a subclass?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steve Edwards

    #1

    Can I avoid rewriting this function in a subclass?

    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_I D>>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
  • Owen Jacobson

    #2
    Re: Can I avoid rewriting this function in a subclass?

    On Sat, 01 Apr 2006 10:28:47 +0100, Steve Edwards wrote:
    [color=blue]
    > Hi,
    >
    > I'm trying to find a simple way to identify which of a heirachy of
    > classes a particular class is:[/color]

    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?

    Comment

    • Steve555

      #3
      Re: Can I avoid rewriting this function in a subclass?


      Owen Jacobson wrote:[color=blue]
      > On Sat, 01 Apr 2006 10:28:47 +0100, Steve Edwards wrote:
      >[color=green]
      > > Hi,
      > >
      > > I'm trying to find a simple way to identify which of a heirachy of
      > > classes a particular class is:[/color]
      >
      > 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?[/color]

      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

      Comment

      • Ivan Vecerina

        #4
        Re: Can I avoid rewriting this function in a subclass?

        "Steve Edwards" <gfx@lineone.ne t> wrote in message
        news:gfx-C56E80.10284701 042006@europe.i sp.giganews.com ...
        : 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_I D>>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).na me()<<endl;
        Mammal* isMammal = dynamic_cast<Ma mmal*>(&a); // NULL if not a mammal
        if( isMammal!=NULL ) cout<<" It is a Mammal !"<<endl;
        Dog* isDog = dynamic_cast<Do g*>(&a); // NULL if not a dog
        if( isDog!=NULL ) isDog->bark();
        IBark* canBark = dynamic_cast<IB ark*>(&a);
        if( isDog==NULL && canBark!=NULL ) //barking plant?
        canBark->bark();
        }

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



        -Ivan
        --
        http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
        Brainbench MVP for C++ <> http://www.brainbench.com


        Comment

        • Steve555

          #5
          Re: Can I avoid rewriting this function in a subclass?


          Ivan Vecerina wrote:[color=blue]
          > "Steve Edwards" <gfx@lineone.ne t> wrote in message
          > news:gfx-C56E80.10284701 042006@europe.i sp.giganews.com ...
          > : 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_I D>>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).na me()<<endl;
          > Mammal* isMammal = dynamic_cast<Ma mmal*>(&a); // NULL if not a mammal
          > if( isMammal!=NULL ) cout<<" It is a Mammal !"<<endl;
          > Dog* isDog = dynamic_cast<Do g*>(&a); // NULL if not a dog
          > if( isDog!=NULL ) isDog->bark();
          > IBark* canBark = dynamic_cast<IB ark*>(&a);
          > if( isDog==NULL && canBark!=NULL ) //barking plant?
          > canBark->bark();
          > }
          >
          > int main()
          > {
          > Mammal a;
          > foo(a);
          > Dog d;
          > foo(d);
          > }[/color]

          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.

          Comment

          • Richard Herring

            #6
            Re: Can I avoid rewriting this function in a subclass?

            In message <1143889061.141 395.101940@u72g 2000cwu.googleg roups.com>,
            Steve555 <foursheds@btin ternet.com> writes[color=blue]
            >
            >Owen Jacobson wrote:[color=green]
            >> On Sat, 01 Apr 2006 10:28:47 +0100, Steve Edwards wrote:
            >>[color=darkred]
            >> > Hi,
            >> >
            >> > I'm trying to find a simple way to identify which of a heirachy of
            >> > classes a particular class is:[/color]
            >>
            >> 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?[/color]
            >
            >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().
            >[/color]
            The obvious[*] solution to _that_ is to have functions such as:

            virtual bool CanBark() const;

            etc.
            [*] Not necessarily a good one ;-(

            --
            Richard Herring

            Comment

            • Jeff Flinn

              #7
              Re: Can I avoid rewriting this function in a subclass?

              Richard Herring wrote:[color=blue]
              > In message <1143889061.141 395.101940@u72g 2000cwu.googleg roups.com>,
              > Steve555 <foursheds@btin ternet.com> writes[color=green]
              >>
              >> Owen Jacobson wrote:[color=darkred]
              >>> On Sat, 01 Apr 2006 10:28:47 +0100, Steve Edwards wrote:[/color][/color][/color]

              ....
              [color=blue][color=green][color=darkred]
              >>> What's the real problem you're solving?[/color]
              >>
              >> 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().
              >>[/color]
              > The obvious[*] solution to _that_ is to have functions such as:
              >
              > virtual bool CanBark() const;
              >
              > etc.
              >
              >[*] Not necessarily a good one ;-([/color]

              Perhaps further abstraction of the operation is required:

              virtual void Communicate()co nst;

              Jeff


              Comment

              Working...