jdunn@polyslo.CalPoly.EDU (Jeff Dunn) (10/10/90)
I posted this to alt.msdos.programmer a couple of days ago, and I meant to cross-post to comp.lang.c++. I goofed the subject line, so c++ was left out. I received mail suggesting a post to c++, and since it seems like a reasonable idea, here it is.. While I'm here, could somebody drop me a line about "acceptable" distributions - usa/na/world? And what does the default distribution 'comp' cover? Damn, I feel like a rookie! :) jdunn@polyslo.CalPoly.EDU ******** I have found a couple of nasty bugs in Turbo C++ 1.0 involving multiple inheritance, plus a bonus bug. I have compiled all of these files using cfront 2.0, and they work fine ("fine" in the last case is a proper error report). In one case, the use of an overridden virtual function uses the method for the base class instead of the method defined on the derived class. In the second case, the 'this' pointer becomes invalid (by 2 bytes) in a method, depending on what class definition was used to send a message to an object created through multiple inheritance. In the last case, proper error reporting is not done for the invokation of a virtual base class constructor using the : construct. Hopefully, this post will save some grief... jdunn@polyslo.calpoly.edu ############################## bug2.c ############################# /* bug2.c Contact me at: Jeff Dunn General Consulting (805) 541-5513 mornings and early afternoons are the best. To be brief, I feel that multiple inheritance in Turbo C++ 1.0 just plain doesn't work. I have spent far too much time tracking down bugs in the compiler, not to mention associated development time lost. The problem here is that a method for a base class is used instead of the method on the derived class which should be used. See the bottom of this file and comments within it for more info. The problem seems to be inheriting Area and InputSensor to derive SenseArea. If I remove Area from the inheritance list or override the cursdown virtual function in the SenseArea class, everything works fine. */ #include <stdio.h> class First {public: First() {printf("\nRunning...\n");}}; First first; typedef void Void; typedef int Int; typedef unsigned long Ulong; typedef unsigned char Bool; class Area { public: Area(); }; inline Area::Area () {printf("Creating Area @ %lx\n", Ulong(this));} // Defines the messages that come from the input devices // Accepts input messages. class InputSensor { public: InputSensor::InputSensor(); virtual void cursdown(); }; InputSensor::InputSensor () {printf("creating InputSensor@%lx\n", Ulong(this)); } void InputSensor::cursdown () {printf("***** InputSensor::cursdown()\n"); return;} /******************************************* ******************************************** * * If SenseArea is given a cursdown method (to override the one * inherited from InputSensor, everything is happy. * */ class SenseArea: public Area, public InputSensor { public: SenseArea(); // virtual void cursdown(); }; inline SenseArea::SenseArea () {printf("Creating SenseArea @ %lx\n", Ulong(this));} //void SenseArea::cursdown () // {printf("SenseArea::cursdown()\n");} class SenseGroup: public SenseArea { public: SenseGroup(); virtual void cursdown(); }; SenseGroup::SenseGroup() {printf("creating SenseGroup @ %lx\n", Ulong(this));} void SenseGroup::cursdown () {printf("SenseGroup::cursdown()\n");} class Input : public SenseGroup { public: Input(); // initialize input system virtual void cursdown(); // inherited from SenseGroup }; void Input::cursdown () { printf("***** Input::cursdown()\n"); } /*************************************************** * **** **** * * ** * * * * * * * ** * * * * * ** ** * * * * * * * ** * * * * * * * ***** **** **** * * ** If I call the input object as type Input, Input::cursdown is called properly, but if I call it as an object of type InputSensor, it calls InputSensor::cursdown(). Since cursdown is a virtual function, Input::cursdown should ALWAYS be used. ***************************************************/ Input::Input () { InputSensor *sthis= this; printf("Creating Input@%lx\n", Ulong(this)); printf("this:%lx sthis:%lx testing Input::cursdown()\n", Ulong(this), Ulong(sthis)); /***************** * * Here it is! * */ printf("as Input\n"); this->cursdown(); printf("as InputSensor\n"); sthis->cursdown(); printf("test done\n"); } /*************************************** * * main, et cetera * */ Input input; int main () { printf("main called\n"); return 0; } #################################### bug1.c ############################### /* bug1.c Jeff Dunn General Consulting (805) 541-5513 Mornings and early afternoons are best. I expect to be contacted about this problem. I have spent far too much time tracking down bugs in the Turbo C++ 1.0 compiler. This is not to mention the development time lost in the process. My main complaint is that multiple inheritance just doesn't seem to be very well tested at all. The problem is in using multiple inheritance and calling an object as the second (or later, I assume) class in the inheritance declaration list. However, this is only true when using a virtual function inherited from the second class that has been overridden and returns an object by value. See comments main for more detail */ #include <stdio.h> #include <string.h> /**************** * * State is the object returned from the virtual function in question. * If it is a simple type (int), everything is fine. If State is a class * object, the program barfs when it runs. * */ #define STATE_OBJECT #ifndef STATE_OBJECT typedef int State; #else class State { public: int value; State(int newval) {value= newval;} }; #endif //STATE_OBJECT // Generic base class class Myobject {}; // Base class class Base { public: virtual State print(); }; State Base::print() {return 0;} // Derived class class Derived: public Myobject, public Base { char name[80]; public: Derived(); virtual State print(); }; Derived::Derived() {strcpy(name, "hello, world!");} State Derived::print() { printf("Derived::print. this:%lx name:%lx %s\n", this, name, name); return 0; } void main () { /****************** LOOK HERE!! **************************/ Derived *derived= new Derived; Base *base= derived; printf("\n"); /* Depending on what type the object is being referenced as, the 'this' pointer in Derived::print is different. On my machine, the difference was two bytes, causing the message to be shortened to "llo, world!" in the second use of the print method. Not a bad thing to say, but not what I wanted. :-) */ derived->print(); base->print(); } ################################## bug3.c ################################# /* bug3.c There is a problem with using the : construct to send parameters to the constructor for a virtual base class. When using this, the error message I get is "Destructor for Code required in conditional expression in function Class3::Class3(Code)." There is no conditional near this line, and the presence of a constructor makes no difference whatsoever. This should report an error because a constructor with no parameters must exist for virtual base classes, and the explicit call to the constructor of the base class (the : construct) should not be allowed. */ #undef BYREF class Code { int code; public: Code(int acode); }; Code::Code(int acode) :code(acode) {} class Class1 { Code a; public: #ifdef BYREF Class1(Code &aa); #else Class1(Code aa); #endif }; #ifdef BYREF Class1::Class1 (Code &aa) :a(aa) {} #else Class1::Class1 (Code aa) :a(aa) {} #endif /****************************** * * If Class1 is declared as a non-virtual base class, everything works * fine. * */ class Class3: virtual public Class1 { public: Class3(Code ag); }; Class3::Class3(Code ag) :Class1(ag) {} -- TALK HARD -- TALK HARD