shape myShape;Μιά τέτοια εντολή προξενεί μήνυμα λάθους από τον compiler. Μιά κλάση χαρακτηρίζεται αφηρημένη όταν έχει μιά τουλάχιστον virtual συνάρτηση με μηδενικό σώμα, όπως π.χ.
virtual void printEq() const = 0;virtual (εικονική) σημαίνει ότι κάθε υποκλάση που θα δημιουργηθεί, πρέπει να ορίσει την δική της συνάρτηση αυτού του τύπου. Η συγκεκριμένη συνάρτηση είναι αυτή που μου τυπώνει την εξίσωση του σχήματος. π.χ. γιά μιά ευθεία line τυπώνει κάτι σαν το:
aX + bY + c = 0ενώ γιά έναν κύκλο circle τυπώνει κάτι σαν το
X2 + Y2 + aX + bY + c = 0 .Στο σύστημα λοιπόν των τριών κλάσεων που θα φτιάξω, θα υπάρχουν τρεις συναρτήσεις της ίδιας μορφής, αλλά με διαφορετικό σώμα η κάθε μιά:
virtual void printEq() const = 0; χωρίς σώμα στην αφηρημένη κλάση shape virtual void printEq() const { ... σώμα συνάρτησης της κλάσης line ...} virtual void printEq() const { ... σώμα συνάρτησης της κλάσης circle ...}Παραθέτω αμέσως τους ορισμούς των τριών κλάσεων:
#ifndef LINE #define LINE /*-------------------------------------------------------------------------- ABSTRACT class shape ----------------------------------------------------------------------------*/ class cmx; // an experimental abstract class, to be used to implement // 1) lines defined though two points // 2) circles defined by center and one point on circle class shape { private: void copy(const shape & other); protected: cmx pts[2]; public: shape(); shape(const shape & other) ; shape(cmx* points) ; shape & operator=( const shape & other ); void setPts(cmx const* ps) ; void printPoints(bool newline=false) const; // common to both line, circle virtual ~shape(); virtual void equation(double * c) const = 0; virtual void PtsFromc( double * c ) = 0; virtual void printEq() const =0; virtual double eval( const cmx & z ) const = 0; }; /*-------------------------------------------------------------------------- class line deriving from abstract class shape ----------------------------------------------------------------------------*/ class line : public shape { public: line(); line(const line & other) ; line(cmx* points) ; line & operator=( const line & other ); virtual ~line() ; virtual void equation(double * c) const ; virtual void PtsFromc( double * c ) ; virtual void printEq() const; virtual double eval( const cmx & z ) const ; }; /*-------------------------------------------------------------------------- class circle deriving from abstract class shape ----------------------------------------------------------------------------*/ class circle : public shape { public: circle(); circle(const circle & other) ; circle(cmx* points) ; circle & operator=( const circle & other ); virtual ~circle() ; virtual void equation(double * c) const ; virtual void PtsFromc( double * c ) ; virtual void printEq() const; virtual double eval( const cmx & z ) const ; }; #endif // LINE
void setPts(cmx const* ps) ; void printPoints(bool newline=false) const; // common to both line, circleΗ πρώτη δίνει τιμές στα δύο σημεία που ορίζουν τον κύκλο ή την ευθεία. Η δουλειά είναι η ίδια και στις δύο περιπτώσεις, άρα τοποθετείται εδώ (στην αφηρημένη μητέρα κλάση).
#include "comx.h" #include "line.h" #include "cmxFunctions.h" #include <iostream.h> #include <math.h> /*-------------------------------------------------------------------------- ABSTRACT class shape ----------------------------------------------------------------------------*/ shape::shape(){} shape::~shape(){} shape::shape(const shape & other) { copy(other);} shape::shape(cmx* points) {pts[0]=points[0]; pts[1]=points[1];} shape & shape::operator=( const shape & other ) { if(this == &other) return *this; copy(other); return *this; } void shape::copy(const shape & other) { pts[0]=other.pts[0]; pts[1]=other.pts[1]; } void shape::setPts(cmx const* ps) {pts[0]=ps[0]; pts[1]=ps[1];} void shape::printPoints(bool newline) const { for(int i=0;i<2;i++) { cout << "pt(" << i << ")= " ; pts[i].print(); cout << " "; } if(newline) cout << endl; } /*-------------------------------------------------------------------------- class line deriving from abstract class shape ----------------------------------------------------------------------------*/ line::line(){} line::line(const line & other):shape(other){} line::line(cmx* points):shape(points){} ; line & line::operator=( const line & other ) { shape::operator =(other); return *this; } line::~line() {} void line::equation(double * c) const { c[0] = pts[0].y-pts[1].y; c[1] = pts[1].x-pts[0].x; c[2] = -(c[0]*pts[0].x + c[1]*pts[0].y); } void line::PtsFromc( double * c ) { cmx diff(-c[1], c[0] ); double lamda = (-c[2]/(c[0]*c[0]+c[1]*c[1])); // warning pts[0].x = lamda*c[0]; pts[0].y = lamda*c[1]; pts[1] = pts[0] + diff; } void line::printEq() const { double c[3]; equation(c); cout << c[0] << "X + " << c[1] << "Y + " << c[2] << " = 0 \n"; } double line::eval( const cmx & z ) const { double c[3]; equation(c); return c[0]*z.x + c[1]*z.y+ c[2]; } /*-------------------------------------------------------------------------- class circle deriving from abstract class shape ----------------------------------------------------------------------------*/ circle::circle(){} circle::circle(const circle & other):shape(other){} circle::circle(cmx* points):shape(points){} ; circle & circle::operator=( const circle & other ) { shape::operator =(other); return *this; } circle::~circle() {} void circle::equation(double * c) const { c[0] = -2.*pts[0].x; c[1] = -2.*pts[0].y; c[2] = 2.*inner(pts[0],pts[1])-inner(pts[1],pts[1]); } void circle::PtsFromc( double * c ) { pts[0].x = - 0.5* c[0]; pts[0].y = - 0.5* c[1]; double critical = inner(pts[0],pts[0])-c[2]; if( critical < 0.0 ) { cout << " ERROR no real circle " << endl; pts[1]= pts[0]; // warning ??????? } else { double radius = sqrt( critical ); pts[1].x = pts[0].x + radius; pts[1].y = pts[0].y; } } void circle::printEq() const { double c[3]; equation(c); cout << "X2+Y2+ " << c[0] << "X + " << c[1] << "Y + " << c[2] << " = 0 \n"; } double circle::eval( const cmx & z ) const { double squares = inner(z,z); double c[3]; equation(c); return squares + c[0]*z.x + c[1]*z.y+ c[2]; }
line::line(const line & other):shape(other){} | Ο κατασκευαστής-αντιγραφής, καλεί απλά τον αντίστοιχο της μητέρας κλάσης. Το ίδιο συμβαίνει και με τον αντίστοιχο κατασκευαστή της circle. |
line & line::operator=( const line & other ) { shape::operator =(other); return *this; } | Ο τελεστής ισότητας της line καλεί τον αντίστοιχο της μητέρας κλάσης και επιστρέφει το ίδιο το αντικείμενο: (*this) που είναι το αριστερό μέλος της ισότητας. |
void line::equation(double * c) const |
Συνάρτηση που υπολογίζει τα c[0], c[1], c[2] που παριστούν τους συντελεστές της εξίσωσης της
ευθείας: c[0]x + c[1]y + c[2] = 0. Η ομόνυμη συνάρτηση της circle υπολογίζει τους αντίστοιχους συντελεστές της εξίσωσης του κύκλου: x^2+y^2 + c[0]x + c[1]y + c[2] = 0. Το πρόβλημα είναι ότι σε κάθε κλάση χρειάζεται ένας διαφορετικός τρόπος υπολογισμού αυτών των συντελεστών από τους δύο μιγαδικούς pts[0] και pts[1]. Ετσι κάθε κλάση έχει την δική της συνάρτηση γι αυτόν τον υπολογισμό. |
void line::PtsFromc( double * c ) |
Συνάρτηση που κάνει την αντίστροφη δουλειά από την προηγούμενη. Δηλαδή υπολογίζει τα
σημεία pts[0] και pts[1] από τα c[0], c[1], c[2] που παριστούν τους συντελεστές
της εξίσωσης της ευθείας: c[0]x + c[1]y + c[2] = 0. Η ομόνυμη συνάρτηση της circle κάνει τα ανάλογα για τον κύκλο. |
void line::printEq() const |
Συνάρτηση που τυπώνει την εξίσωση της ευθείας Η ομόνυμη συνάρτηση της circle κάνει τα ανάλογα για τον κύκλο. |
#include "comx.h" #include "line.h" #include <iostream.h> int main(int argc, char* argv[]) { cmx a[2] = { cmx(1.,1.), cmx( 1.0, 0.0) }; cmx b[2] = { cmx(-1.,0.), cmx( 0.0, 1.0) }; line aLine(a); line bLine(b); aLine.printEq(); bLine.printEq(); // sign printing problem ?? double c[3] = { -1. , 1. , -1. }; line cLine; cLine.PtsFromc(c); cLine.printEq(); circle aCircle(a); circle bCircle(b); aCircle.printEq(); bCircle.printEq(); circle cCircle; cCircle.PtsFromc(c); cCircle.printEq(); return 0; }
shape & shape::operator=( const shape & other ) { if(this != &other) copy(other); return *this; }Εξήγησε τι είναι το this και τι κάνει η συνάρτηση αυτή.