Path: utzoo!attcan!uunet!ncrlnk!ncrcae!hubcap!gatech!bloom-beacon!apple!oliveb!ames!hc!lanl!lambda!scp From: scp@raven.lanl.gov (Stephen Pope) Newsgroups: comp.lang.c++ Subject: Re: virtual vs. non-virtual functions. Message-ID: Date: 10 Mar 89 20:33:00 GMT References: <202@ncr-fc.FtCollins.NCR.COM> Sender: news@lanl.gov Followup-To: comp.lang.c++ Distribution: na Organization: The Santa Fe Institute, NM Lines: 82 In-reply-to: frodo@ncr-fc.FtCollins.NCR.COM's message of 9 Mar 89 22:58:57 GMT David Fletcher writes <202@ncr-fc.FtCollins.NCR.COM>: > Adding the keyword virtual buys me 2 things (as I understand it): > 1. I can assure that the return type of the redefined virtual function > is compatible with the original version. When base's Value() function > is vitual and returns an int and derived's Value() function returns a > long then CC gives me an error (as I would expect it to). If Value() is > not virtual & in the derived class I declare it to return a long then > the compiler is quite happy. > 2. A call to Value() via a pointer to an object (of type base OR derived) > would call the correct version of Value(). This is explained fairly > well in "The C++ Book." > I guess what my question boils down to is that I thought data would > be inherited and (member) functions wouldn't UNLESS a function was > declared virtual. The behavior you observe is correct. As long as your derived class is *publically* derived from the base class, all protected and public members *and* member functions are visible to the derived class. The 1st point above is not a *reason* for the virtual keyword, but rather a consequence of it. Point 2 is the _meat_and_potatoes_ of the issue: If a derived class overloads a non-virtual base class definition, then invocations of the said member function from a pointer to the base class (regardless of whether the pointer is actually pointing to a base class or derived class object) will always invoke the base class method. That is: class B { public: void func() { cout << "Base\n"; }; }; class D : public B { public: void func() { cout << "Derived\n"; }; }; main() { B b; D d; B *bp; b.func(); // prints "Base" d.func(); // prints "Derived" bp = &b; bp->func(); // prints "Base" bp = &d; bp->func(); // prints "Base" } If, however, func had been declared virtual in class B, the last statement above would generate "Derived", not "Base". The issue is that the virtual declaration insures that invocations of a member function are called by looking up a function's address in the virtual pointer table, thus the proper derived version will be called even when referenced through a pointer to the base class. If the member function is not a virtual, it has no entry in the virtual pointer table, and since all the compiler knows is that it has a pointer to base class, the best it can do is invoke the member function *for the base class*. It has no way of knowing that the object pointed to might be anything other than the base class! This also brings up an issue skirted a little while ago: why can't a virtually overloaded member function return different types in for derived class than for the base class. The fact is that if all you have is a pointer to a base class, and you invoke a virtual member function, you *must* know exactly what is being returned. Since all you know is the base class properties, the derived class version better return the same data type, or else you will munge the return value horribly. Only in a language with self-identifying (tagged) data structures could you return differing types. Stephen C. Pope The Santa Fe Institute scp@santafe.edu