frodo@ncr-fc.FtCollins.NCR.COM (David Fletcher) (03/10/89)
Hello. First of all, this is under AT&T 1.2.1 cfront. I have a base class, B, and a publicly derived class, D. The base class defines a non-virtual public member function, Value(), that returns the value of some protected entry. D does not define this member function (&, again, Value() is not virtual). Out of curiosity I tried: . . B SomeDooDad; D OtherDooDad; cout << "B's value is " << SomeDooDad.Value() "\n"; cout << "D's value is " << OtherDooDad.Value() "\n"; . . This works but I didn't expect it to & don't understand why. I thought that only virtual functions (defined in a based class) would be defined for the derived class. If that's not the case then why even have the virtual keyword? Is this a bug? Am I wrong? Thanks for the help. -- David Fletcher, NCR Microelectronics 2001 Danfield Court, Ft. Collins, CO 80525 | "... Let everything else go ..." (303) 223-5100 x 241 | -- Phil Keaggy
beard@ux3.lbl.gov (Patrick C Beard) (03/10/89)
I am under the impression that the virtual keyword implies that a function is redefinable in a derived class. A non-virtual function isn't, and so is callable from derived classes. It would have worked as well if you had declared "Value" as virtual, and you would have been able to define a new version of Value() for the derived class D. Correct me if I'm wrong, I'm fairly new to C++ as well. +----------------------------------------------------------------+ \ Patrick Beard "Badges? \ \ Berkeley Systems, Inc. I ain't got to show you... \ \ PCBeard@lbl.gov ...NO STINKING BADGES!" \ + ---------------------------------------------------------------+
frodo@ncr-fc.FtCollins.NCR.COM (David Fletcher) (03/10/89)
// In response to my original question Patrick Beard writes:
I am under the impression that the virtual keyword implies that a
function is redefinable in a derived class. A non-virtual function
isn't, and so is callable from derived classes. It would have worked
as well if you had declared "Value" as virtual, and you would have been
able to define a new version of Value() for the derived class D.
I agree with most of what you say but I *can* redefine the function in
the derived class. In fact, on page 194 of "The C++ Programming
Language" an example is given showing that the non-virtual function can
be redefined in the derived (manager) class.
What I don't understand is why the Value() function, if declared in only
the base class in a non-virtual way, is visible to the derived class.
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. Thanks again for any help (Thanks, too, Patrick).
--
David Fletcher, NCR Microelectronics
2001 Danfield Court,
Ft. Collins, CO 80525 | "... Let everything else go ..."
(303) 223-5100 x 241 | -- Phil Keaggy
scp@raven.lanl.gov (Stephen Pope) (03/11/89)
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
kanner@Apple.COM (Herbert Kanner) (03/11/89)
In article <202@ncr-fc.FtCollins.NCR.COM> frodo@ncr-fc.UUCP (David Fletcher) writes: >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. Thanks again for any help (Thanks, too, Patrick). > > >-- >David Fletcher, NCR Microelectronics >2001 Danfield Court, >Ft. Collins, CO 80525 | "... Let everything else go ..." >(303) 223-5100 x 241 | -- Phil Keaggy Here are the facts. Both virtual and non-virtual member functions are inherited from a base class to a derived class, and either of them can be overriden in a derived class. The distinction between virtual and non-virtual functions is the non-virtul function are *always* bound at compile time, while virtual function will, under the right circumstances be bound at run time. The circumstance under which binding takes place at run time is the following: class Base { public: virtual void f(); }; class Derived : public Base { void f(); }; Base* ptr; ptr = new Base; ptr->f(); // will call the f() in Base ptr = new Derived; ptr->f(); //will call the f() in Derived Had the function not been declared virtual, both calls would have been to the f() in Base, because the decision would have been made at compile time and would have been determined by the type of ptr. -- Herb Kanner Apple Computer, Inc. {idi,nsc}!apple!kanner kanner@apple.com