keith@csli.Stanford.EDU (Keith Nishihara) (10/11/89)
I was surprised to discover that calling delete on a derived class object pointed to by a pointer to the base class failed to call the derived class destructor. (cfront 1.2) (See example below.) I cannot think of any case where this would be the desirable behaviour. Fortunately, it appears that declaring the destructor virtual causes the appropriate behaviour to happen. Why are not all desctructors virtual? Is this true in other C++ systems? Example: class base { public: base(); ~base() { printf("Base destructor\n); } private: // more stuff. }; class derived : public base { public: derived(); ~derived() { printf("Derived destructor.\n"); } private: // more stuff. }; main() { base *p = new derived; delete p; // "Base destructor" derived *q = new derived; delete q; // "Derived destructor" // "Base destructor" } Neil/.
jima@hplsla.HP.COM (Jim Adcock) (10/12/89)
>keith@csli.Stanford.EDU (Keith Nishihara) / 5:55 pm Oct 10, 1989 / >I was surprised to discover that calling delete on a derived class >object pointed to by a pointer to the base class failed to call >the derived class destructor. (cfront 1.2) (See example below.) >I cannot think of any case where this would be the desirable behaviour. >Fortunately, it appears that declaring the destructor virtual causes >the appropriate behaviour to happen. Why are not all desctructors >virtual? Is this true in other C++ systems? Well, one answer is that declaring a function virtual causes both a space penalty in an object of that class [said penalty constant as long as one or more virtual functions are declared] and also a time penalty in invoking that virtual function. Presumably, if someone gives you a class with a non-virtual destructor and you'd rather have a virtual destructor, then you can trivially derive a new class that has a virtual destructor. But you can't go the other way. Once a superclass declares a virtual function subclasses always get to eat the space and/or time penalties. This behavior is true of all C++ I have seen. If you want a function to be virtual, declare it virtual. This requirement also has the advantage of language consistency.
shopiro@alice.UUCP (Jonathan Shopiro) (10/15/89)
In article <10627@csli.Stanford.EDU>, keith@csli.Stanford.EDU (Keith Nishihara) writes:
- I was surprised to discover that calling delete on a derived class
- object pointed to by a pointer to the base class failed to call
- the derived class destructor. (cfront 1.2) (See example below.)
- I cannot think of any case where this would be the desirable behaviour.
- Fortunately, it appears that declaring the destructor virtual causes
- the appropriate behaviour to happen. Why are not all desctructors
- virtual? Is this true in other C++ systems?
It's true at least in C++ 2.0. The reason why is that some classes
have no virtual functions, and adding a virtual destructor would cost
one word per object of the class. Some classes are not intended to be
inherited from, so they don't need any virtual functions. I think it's
generally true that if a class has any virtual functions, it should
have a virtual destructor, but it's up to you to do it.
--
Jonathan Shopiro
AT&T Bell Laboratories, Warren, NJ 07060-0908
research!shopiro (201) 580-4229
mce@tc.fluke.COM (Brian McElhinney) (10/17/89)
In article <6590296@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: >>keith@csli.Stanford.EDU (Keith Nishihara) / 5:55 pm Oct 10, 1989 / >>the appropriate behaviour to happen. Why are not all desctructors >>virtual? Is this true in other C++ systems? > >Well, one answer is that declaring a function virtual causes both a space >penalty in an object of that class [said penalty constant as long as one >or more virtual functions are declared] and also a time penalty in invoking >that virtual function. This isn't a requirement of the C++ language definition, is it? I understood it to be a result of the cfront implementation (eg, relying on standard C and its linker). I would expect more advanced C++ compilers to optimize this case; if a virtual method is never overloaded, call the method directly. >This behavior is true of all C++ I have seen. If you want a function to >be virtual, declare it virtual. This requirement also has the advantage of >language consistency. And the disadvantage of requiring the original author to anticipate exactly which methods I will need to override. You shouldn't need to change "resuable" source code in order to reuse it. Brian McElhinney "Knowledge is soon changed, then lost in the mce@tc.fluke.com mist, an echo half-heard" --Gene Wolfe
dml@esl.com (Denis Lynch) (10/18/89)
In article <11748@fluke.COM> mce@tc.fluke.COM (Brian McElhinney) writes: In article <6590296@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: >>keith@csli.Stanford.EDU (Keith Nishihara) / 5:55 pm Oct 10, 1989 / >>the appropriate behaviour to happen. Why are not all desctructors >>virtual? Is this true in other C++ systems? > >Well, one answer is that declaring a function virtual causes both a space >penalty in an object of that class [said penalty constant as long as one >or more virtual functions are declared] and also a time penalty in invoking >that virtual function. This isn't a requirement of the C++ language definition, is it? I understood it to be a result of the cfront implementation (eg, relying on standard C and its linker). I would expect more advanced C++ compilers to optimize this case; if a virtual method is never overloaded, call the method directly. >This behavior is true of all C++ I have seen. If you want a function to >be virtual, declare it virtual. This requirement also has the advantage of >language consistency. And the disadvantage of requiring the original author to anticipate exactly which methods I will need to override. You shouldn't need to change "resuable" source code in order to reuse it. I find this an interesting juxtaposition of arguments, Brian. First, the "smart compiler" problem. Since reusable code is likely to go in a library, the compiler can't possibly tell whether an operator is overloaded. Unless you expect to have access to the source code for all your libraries, which the library vendors aren't likely to be excited about. Second, the "anticipation" problem. Here, you must be arguing that you want *all* member functions to be virtual, i.e. overridable. If that's what you want, you don't need a smart compiler or a language change, just declare all your functions virtual. The current language gives you the option of writing member functions that you *know* will not be overriden, and others that may be. This is a reasonable extension of the public/private/protected distinctions: you can have code that is guaranteed to call the function you wrote, never a client's "better idea." Or did I miss something? Denis Lynch dml@esl.com
mce@tc.fluke.COM (Brian McElhinney) (10/21/89)
In article <DML.89Oct17135223@bloch.esl.com> dml@esl.com (Denis Lynch) writes: >First, the "smart compiler" problem. Since reusable code is likely to go in a >library, the compiler can't possibly tell whether an operator is overloaded. >Unless you expect to have access to the source code for all your libraries, >which the library vendors aren't likely to be excited about. Actually, I do expect that I will commonly have access to all sources (but then I work for a medium sized company that can afford it). You are right in that there will be exceptions, and the compiler/linker have to handle it. I don't see it being a very difficult problem (as long as we are taling about a "true" C++ compiler/linker, instead of being limited to what C can do). >Second, the "anticipation" problem. Here, you must be arguing that you want >*all* member functions to be virtual, i.e. overridable. If that's what you >want, you don't need a smart compiler or a language change, just declare all >your functions virtual. And take a performance hit (that's what started this thread of discussion). >The current language gives you the option of writing member functions that you >*know* will not be overriden, and others that may be. This is a reasonable >extension of the public/private/protected distinctions: you can have code >that is guaranteed to call the function you wrote, never a client's "better >idea." > >Or did I miss something? The idea is that, for any public routine, the person *using* the code should make the decision, not the original author. C++ takes just the opposite stand. I am sensitive to the reasons why, but I still feel it is a wart in C++. Brian McElhinney "Knowledge is soon changed, then lost in the mce@tc.fluke.com mist, an echo half-heard" --Gene Wolfe