Untitled
unknown
c_cpp
2 years ago
6.3 kB
8
Indexable
// 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;
}
Editor is loading...