Virtual Methods

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Deanm007
    New Member
    • Apr 2010
    • 37

    Virtual Methods

    In the following program, why is the bird's fly method stated as virtual when its implementation is not overridden by any other class method. I thought we only state a method as virtual when you will be overriding it.

    Code:
    #include <iostream>
     
     using namespace std;
    
     class Horse
     {
     public:
     Horse() { cout << "Horse constructor... "; }
     virtual ~Horse() { cout << "Horse destructor... "; }
     virtual void Whinny() const { cout << "Whinny!... "; }
     private:
     int itsAge;
     };
    
     class Bird
     {
     public:
     Bird() { cout << "Bird constructor... "; }
     virtual ~Bird() { cout << "Bird destructor... "; }
     virtual void Chirp() const { cout << "Chirp... "; }
     virtual void Fly() const
     {
     cout << "I can fly! I can fly! I can fly! ";
     }
     private:
     int itsWeight;
     };
    
     class Pegasus : public Horse, public Bird //inheriting from two base classes.
     {
     public:
     void Chirp() const { Whinny(); }
     Pegasus() { cout << "Pegasus constructor... "; }
     ~Pegasus() { cout << "Pegasus destructor... "; }
     };
    
     const int MagicNumber = 2;
     int main()
     {
     Horse* Ranch[MagicNumber];
     Bird* Aviary[MagicNumber];
     Horse * pHorse;
     Bird * pBird;
     int choice,i;
     for (i=0; i<MagicNumber; i++)
     {
     cout << "\n(1)Horse (2)Pegasus: ";
     cin >> choice;
     if (choice == 2)
     pHorse = new Pegasus;
     else
     pHorse = new Horse;
     Ranch[i] = pHorse;
     }
     for (i=0; i<MagicNumber; i++)
     {
     cout << "\n(1)Bird (2)Pegasus: ";
     cin >> choice;
     if (choice == 2)
     pBird = new Pegasus;
     else
     pBird = new Bird;
     Aviary[i] = pBird;
     }
    
     cout << "\n";
     for (i=0; i<MagicNumber; i++)
     {
     cout << "\nRanch[" << i << "]: " ;
     Ranch[i]->Whinny();
     delete Ranch[i];
     }
    
     for (i=0; i<MagicNumber; i++)
     {
     cout << "\nAviary[" << i << "]: " ;
     Aviary[i]->Chirp();
     Aviary[i]->Fly();
     delete Aviary[i];
     }
     cin.get();
     return 0;
     }
  • Oralloy
    Recognized Expert Contributor
    • Jun 2010
    • 988

    #2
    Perhaps the Pegasus will fly differently than a generic Bird?

    In this case it doesn't hurt.

    Personally, I tend to think of all methods as being appropriately virtual, unless there is a compelling reason for them to be otherwise. Performance in real-time systems being one of those reasons.

    Otherwise, code like this example:
    Code:
    class Bird
    {
      char const *Fly() { return "flap"; }
    };
    
    class Pegasus : public Bird
    {
      char const *Fly() { return "flap real hard!"; }
    };
    
    main()
    {
      Pegasus *peg    = new Pegasus();
      Bird    *birdie = peg;
    
      cout << "Pleased to meet you, I'm Peg." << endl;
      cout << "I'm a Bird, watch me fly .... " << birdie->Fly() << endl;
      cout << "I'm a Pegasus, watch me fly .... " << peg->Fly() << endl;
    
      return 0;
    }
    Gives what are usually undesireable results.

    Pleased to meet you, I'm Peg.
    I'm a Bird, watch me fly ... flap.
    I'm a Pegasus, watch me fly ... flap real hard!

    The bottom line is really what you want the behaviour of the software system and components to be. Or maybe what they "should" be, in a more philosophical vein.

    Does that help any?

    Comment

    • Deanm007
      New Member
      • Apr 2010
      • 37

      #3
      So its best to make all base class methods virtual in case they will be overridden. Is that right? I also understand that after the first virtual method, subsequent ones do not take up much memory. Thanks.

      Comment

      • Oralloy
        Recognized Expert Contributor
        • Jun 2010
        • 988

        #4
        Make methods virtual, depending on their use.

        Class specific (helper) methods don't need to be virtual, unless they're exposed publically. Right? They're private to a particular class, and as such aren't even visible to derived classes.

        General action methods, however, will likely be virtual, otherwise where's the value in having derived classes?

        Accessors and settors are usually fine as non-virtuals, too. But ... this can depend on how a class is to be used. If you're writing code where accessors and settors are being overridden, make sure your reasoning is sound, and your documentation very clear.

        Predicate methods (e.g. isAlive, isOpen, etc.) will depend on object use. Remember that an accessor for a boolean attribute is not the same as a predicate, even though they both return bool. The meaning of attributes is very important in software development. Document clearly, so there is never doubt about the meaning of things.

        So what have I said? In too many words - chose your representation based on intended use and meaning. Once your code is implemented into a large system, correcting little design mistakes can rapidly become intractible.

        Regarding memory, any object with a virtual method will have a v-table reference for that object's class. The per-object overhead is fixed, regardless of the number of virtual methods. And frankly, the v-table its self is so small, that the cost is negligable in the scheme of things.

        cheers!

        Comment

        • Deanm007
          New Member
          • Apr 2010
          • 37

          #5
          Thanks a lot Oralloy. This is one of the most precise answers I have received.

          Comment

          • Oralloy
            Recognized Expert Contributor
            • Jun 2010
            • 988

            #6
            @Deanm007

            You're welcome.

            Have a great evening.

            Comment

            Working...