I am having a major algorithm design issue with writing to a file. I have thought about this for quite some time now (I even perused Stroustrup with no luck), but I'm just spinning my wheels, so I was hoping for somebody to at least point me in the right direction. Here's the situation... I create an ellipse object (defined by its major and minor radii and its center coordinate). An ellipse is a child class of the closed_curve base class. I have been asked to write a method called "print_curve" that takes the number of points to plot and a file name to output to. This method needs to be defined in the base class (closed_curve). An ellipse object (in main.cpp) needs to call this method to create a file of points, such that I can load this csv file into Excel for the actual plotting. I was told that I should write only one method for this, but I think this is impossible. I think I need to create the base method (print_curve), along with a method for ellipse, since I need to tell print_curve how to plot the points (the points are given by ellipse's place method).
Here are my files:
"coordinate.h"
1 2 3 4 5 6 7 8 9 10 11 12
#ifndef COORDINATE_H_
#define COORDINATE_H_
class coordinate
{
public:
coordinate(); // empty constructor
coordinate(double x_holder, double y_holder); // constructor with parameters
double x, y; // the coordinates
};
#endif
"coordinate.cpp"
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include "coordinate.h"
// empty constructor of coordinate object:
coordinate::coordinate()
{
}
// constructor of coordinate object with parameters:
coordinate::coordinate(double x_holder, double y_holder)
{
x = x_holder;
y = y_holder;
}
"closed_curve.h"
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#ifndef CLOSED_CURVE_H_
#define CLOSED_CURVE_H_
#include "coordinate.h"
class closed_curve
{
public:
virtual coordinate place(double) = 0; // returns a coordinate from a parametric position equation
void print_curve(int N, char Name[]); // outputs a file for the plotting of an object
// I think that print_curve shouldn't be virtual (its implementation shouldn't change whether I am constructing an ellipse, a square, etc.), but I'm not sure on this.
};
#endif
"closed_curve.cpp"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include "closed_curve.h"
#include <fstream>
usingnamespace std;
// output x and y coordinates to a file for N points:
void closed_curve:print_curve(int N, char Name[])
{
double h = 1/N; // partition the curve to plot
for (int i = 1; i <= N; i++)
{
ofstream writeFile(Name[]);
writeFile << << endl; // this is incomplete, but I don't know what to put in this line
}
writeFile.close();
}
#include "ellipse.h"
#include "coordinate.h"
#include <math.h>
// constructor:
ellipse::ellipse(double a, double b, double x, double y) : major_radius(a), minor_radius(b), center(x,y)
{
}
// return the coordinates for a point on the curve:
coordinate ellipse::place(double t)
{
double pi = 3.14159265;
coordinate ellipse_coordinate(center.x + major_radius*cos(2*pi*t), center.y + minor_radius*sin(2*pi*t));
return ellipse_coordinate;
}
// return a file for points on the curve:
void ellipse::output_file(int N, char Name[])
{
// I know that I need more code here, but I have no idea what to put here
closed_curve::print_curve(N, Name[]);
}
It is possible but your task involves creating a design flaw:
6 7 8 9 10 11 12 13 14 15 16 17 18 19
void closed_curve::print_curve(int N, char Name[])
{
ellipse *e = dynamic_cast<ellipse*>(this);
if(!e) return; //we're not an ellipse so we don't know what to do
double h = 1/N; // partition the curve to plot
for (int i = 1; i <= N; i++)
{
ofstream writeFile(Name[]);
writeFile << e->center./*I think you know the rest*/ << endl;
}
writeFile.close();
}
Instead of e->center.x, I need to get the x (and, similarly, y) coordinate from the place method. Would the following work?:
1 2 3 4 5 6 7 8 9 10 11 12
double h = 1/N;
double t = 0;
ofstream writeFile(Name[]);
while (t <= 1 - h)
{
writeFile << e->place(t) << "," << e->place(t) << endl;
t = t + h;
}
writeFile.close();
Moreover, since I will be defining many other types of objects (i.e., circle, rectangle, and square), would it be best to duplicate the code you wrote for each type of object?
I'm getting another not-so-descriptive error with this implementation, now:
../circle.h:12: warning: 'circle::center' will be initialized after
../circle.cpp:6: warning: base 'ellipse'
../circle.cpp:6: warning: when initialized here
which, I think is coming from my circle constructor:
All your instructor is asking for is a file with a list of points to plot. Points don't need the context of their generation to be plotted. All you have to do is generate the points to plot and put them in a file in the correct format.
You have a pure virtual function in closed_curve "place" which must be overriden by any derived classes. Given this, you can use a base class function to call the virtual "place" and generate the coordinates you need without knowing the actual type of the class instance you are working with.
So your code becomes something like:
1 2 3 4 5 6 7 8 9 10 11 12 13
void closed_curve::print_curve(int N, char Name[])
{
// prepare for calling place...
std::ofstream out(Name) ;
for (int i = 0; i < N; i++)
{
coordinate c = place( /* variable name goes here */ ) ;
out << c.x << ',' << c.y << '\n';
// update variable to feed to place
}
}
However, all this work is causing another issue in another child class (circle). My code for "circle" was working before I started writing my print_curve method, so I'm surprised why it's just now throwing errors. Any ideas?
Here is the error:
../circle.h: In constructor 'circle::circle(double, double, double)':
../circle.h:12: warning: 'circle::center' will be initialized after
../circle.cpp:6: warning: base 'ellipse'
../circle.cpp:6: warning: when initialized here
When you're dealing with derived and base class construction, the base class construction is always the first thing done in the derived class constructor, regardless of how you arrange the initializer list. Not coincidentally the members of any class are initialized in the order they're listed in the class definition, regardless of the order of the initializer list in the constructor.
You already have a member center in ellipse. Do you need a radius member in circle, or can you define it in terms of the major_radius and minor_radius you already have as members of ellipse?
The center of a circle object will not necessarily be the same as the center of an ellipse object. However, in the spirit of inheritance, I think that it would be better to define radius for a circle in terms of major_radius and minor_radius from an ellipse. I just don't know how to implement this.
Thank you all very much for your help. I was able to implement all my geometrical objects correctly (and, moreover, efficiently), now. (I let circle use ellipse's area and place methods, as well as its center member. I also let square use rectangle's area, circumference, and place methods, as well as its center member.) I can post the code if interested.