Untitled

mail@pastecode.io avatar
unknown
c_cpp
a year ago
6.3 kB
1
Indexable
Never
// Written by Prof. Raymond Klefstad for ICS 141 Programming Languages at University of Calfironia, Irvine
// I limit myself to C feature for this code, but use the C++ compiler, g++, to allow me to use C++ I/O.
// I implemented only base class Circle and derived class ACircle which you can use as an analogy for HW2.


// Replace class Picture with a C array of shape pointers created local to main().
// Write the Picture methods as functions with the same name they were given in Picture.
// Step A) for each concrete class do the following:
//     1) define a C struct for the data in each class instance plus the Vpointer
//     2) define member functions
//       a) add _this formal parameter
//       b) prefix methods with _this->
//     3) define vtable
//     4) define constructor
//       a) must call the parent constructor
//       b) must set the vpointer

// Step B) Write the main, declare the array of shapes,
// allocate each specific shape and construct each one




// #includes to allow us to call malloc() and to do I/O

    #include <malloc.h>
    #include <iostream>
    using namespace std;


    // A vtable is an array of method pointers.
    // The specific profile for each method will depend on how the programmer declared the parameters and return type.

    // In this example, the methods all return type double, and they only take the this parameter.
    // The methods draw() and area() from your HW1 have different return types (so I defined the union below for you
    // to use in your homework).

    typedef double (*double_method_type)(void *);
    typedef void (*void_method_type)(void *);

    typedef union {
        double_method_type double_method; // this is for area()
        void_method_type void_method;     // this is for draw()
    } VirtualTableEntry;

    typedef VirtualTableEntry * VTableType;


// These are the indices of the virtual functions in this class hierarchy, starting 0, 1, ...
    #define AREA_INDEX 0
    #define CIRCUMFERENCE_INDEX 1
    #define NEXT_METHOD_INDEX 2

    #define PI 3.14159

// Start of Class Circle


    struct Circle
    {
        // VPointers for all objects must be in the same location within the object, so declare it as the first data member.
        VTableType VPointer;
        double radius;
    };


// Add the class name as a previx to the name of each class method so they are unique and easy to follow. C has no overloading.

    // You must explicitly declare the this parameter, but you can't use the name this because it is a reserved word in C++

    double Circle_area(Circle * _this)
    {

        // Always explicitly prefix every member reference with _this-> because nothing is automatic in C

        return PI * _this->radius * _this->radius;
    }

    double Circle_circumference(Circle * _this)
    {
        return 2.0 * PI * _this->radius;
    }

    // Define the VTable for Circle.  Fill in the methods that are valid for a Circle object. Note the names of the methods.
    // Use a C union because the entries of vtables will be functions with different return types (and possibly parameters too).
    // In this example, the methods both return double and only have the this parameter, but your homework may be different.

    VirtualTableEntry Circle_VTable [] =
    {
        {.double_method=(double_method_type)Circle_area}, // VTable[AREA_INDEX] - the first virtual method
        {.double_method=(double_method_type)Circle_circumference} // VTable[CIRCUMFERENCE_INDEX] - the second virtual method
    };

    // This is Circle contructor. Note it must set the Vpointer then do the initialization done by the user.
    // If this is a derived class, it must first call the base class constructors before setting the Vpointer to Circle_VTable.  Why?

    Circle * Circle_Circle(Circle * _this, double newRadius)
    {
        _this->VPointer = Circle_VTable;
        _this->radius = newRadius;
        // having our constructors return _this allows us to create array of heap objects very easily, see main below...
        // We can do whatever we want to make our life easier since this is the machine level code possibly generated by a compiler.
        return _this;
    }

// End of Class Circle

// Start of Class ACircle

    struct ACircle
        // extends Circle
    {
        VTableType VPointer;
        // Inherited data must be in the same location as it was in parent (base) class
        double radius;
        // Add the new data members added by the programmer in this derived class
        double aData;
    };

// ACircle area method

    double ACircle_area(ACircle * _this)
    {
        return PI * _this->radius * _this->radius / _this->aData;
    }

// ACircle VTable

    VirtualTableEntry ACircle_VTable [] =
    {
        // Notice the values in this vtable.  The method names indicate which methods are called for ACircle objects
        {.double_method=(double_method_type)ACircle_area}, // Over-ride area
        {.double_method=(double_method_type)Circle_circumference} // inherit Circle::circumference
    };

    // The constructor for ACircle. First action is to call parent constructor. Then over-set the VPointer. Then do programmer actions.
    ACircle * ACircle_ACircle(ACircle * _this, double newRadius, double aValue)
    {
        Circle_Circle((Circle *)_this, newRadius); // call parents constructor
        _this->VPointer = ACircle_VTable; // set the vpointer AFTER parent
        _this->aData = aValue;
        return _this;
    }

// End of Class ACircle

int main()
{
    // Define and initialize the list of circles.
    Circle * a [] = {
        Circle_Circle((Circle *)malloc(sizeof(Circle)), 1.0),
        Circle_Circle((Circle *)malloc(sizeof(Circle)), 10.0),
        Circle_Circle((Circle *)malloc(sizeof(Circle)), 100.0),
        (Circle *)ACircle_ACircle((ACircle *)malloc(sizeof(ACircle)),
            1000.0, 2.0),
        (Circle *)ACircle_ACircle((ACircle *)malloc(sizeof(ACircle)),
            10000.0, PI)
        };
    // Print out the area and circumference of each shape
    for (int i=0; i<sizeof(a)/sizeof(*a); i++)
    {
        cout << "Area = " << (a[i]->VPointer[AREA_INDEX]).double_method(a[i]) << endl;
        cout << "Circumference = " << (a[i]->VPointer[CIRCUMFERENCE_INDEX]).double_method(a[i]) << endl;
    }
    return 0;
}