[comp.lang.c++] Turbo C++ 1.0 bugs

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