Untitled
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; }