class cmx { public: double x; double y; public: cmx(); cmx( const cmx & other ); cmx( const double & xx, const double & yy ); virtual ~cmx(); // <-- changed cmx & operator=( const cmx & other ); // <-- added bool operator==(const cmx & other) const; // <-- added void set( const double & xx, const double & yy) ; void setPol( const double & r, const double & angle) ; double re() const; double im() const; cmx syz() const; double norm() const; double argm() const; void print( bool line = false) const; friend cmx operator+( const cmx & a, const cmx & b ); friend cmx operator-( const cmx & a, const cmx & b ); friend cmx operator*( const cmx & a, const cmx & b ); friend cmx operator*( const double & t, const cmx & b ); // <--added friend cmx operator/( const cmx & a, const cmx & b ); // <--added };
virtual ~cmx(); | Η λέξη virtual θα εξηγηθεί αργότερα. Εδώ σημειώνω ότι κλάσεις που ορίζουν υποκλάσεις χρείαζονται virtual destructors. Επειδή στα επόμενα θα ορίσουμε υποκλάσεις της cmx, προετοιμάζουμε το έδαφος από τώρα. |
cmx & operator=( const cmx & other ); | Ο τελεστής ισότητας. Αν δεν τον ορίσουμε όπως κάνουμε εδώ, ο υπολογιστής χρησιμοποιεί αυτόματα έναν δικό του, όταν χρειασθεί. Στην παρούσα περίπτωση ο αυτόματος κάνει την ίδια δουλειά με τούτον τον συγκεκριμένο. |
bool operator==(const cmx & other) const; | Τελεστής σύγκρισης δύο μιγαδικών, ωστε να μπορούμε να γράψουμε ...if(z1==z2) κτλ. |
friend cmx operator*( const double & t, const cmx & b ); | Τελεστής πολλαπλασιασμού μιγαδικού αριθμού με πραγματικό. Δίνει νόημα στην εξίσωση w = t*z όπου z, w μιγαδικοί και t πραγματικός. |
friend cmx operator/( const cmx & a, const cmx & b ); | Ορίζει την διαίρεση δύο μιγαδικών ώστε να μπορούμε να γράφουμε w=z1/z2 ... |
cmx::~cmx(){} cmx & cmx::operator=( const cmx & other ) // <-- added { if(this == &other ) return *this; x=other.x; y=other.y; return *this; } bool cmx::operator==(const cmx & other) const // <-- added { if(x==other.x && y==other.y) return true; return false; } cmx operator*( const double & t, const cmx & b ) // <--added { return cmx(t*b.x, t*b.y); } cmx operator/( const cmx & a, const cmx & b ) // <--added { double q = b.norm(); if(q!=0.0) // warning ??? { return (1.0/q)*(a*(b.syz())); } return cmx(0.0, 0.0); }
if(this == &other ) return *this;Συγκρίνει τις διευθύνσεις της παρούσης μεταβλητής (αριστερό μέλος της ισότητας) και της μεταβλητής other που παριστάνει την δεξιά πλευρά στην ισότητα z = other; Αν οι διευθύνσεις συμπίπτουν τότε επιστρέφει το περιεχόμενο του this (*this) που δεν είναι άλλο από το z. Μ αυτόν τον τρόπο έχουμε την δυνατότητα να γράψουμε μιά σειρά από ισότητες z1 = z2 = z3 = ... zN = w; οι οποίες εκτελούνται διαδοχικά από τα δεξιά προς τα αριστερά και καθιστούν τα περιεχόμενα όλων των μεταβλητών ίσα με το περιεχόμενο της w. Σημείωσε ότι η & κάνει αντίστροφη δουλειά από την *. Ετσι η &other είναι η διεύθυνση μνήμης στην οποία ευρίσκεται η other.
Αυτή η διάκριση μεταξύ μεταβλητής και διεύθυνσης (στην μνήμη του υπολογιστή) στην οποία ευρίσκεται η μεταβλητή είναι πολύ σημαντική στην C++. Τα πράγματα φαίνονται μπλεγμένα στην αρχή, μέχρι να συνηθήσει κανείς. Ιδιαίτερα όταν λάβει υπόψη του ότι μπορούν να ορισθούν μεταβλητές οι οποίες περιέχουν διευθύνσεις άλλων μεταβλητών. π.χ.
int n = 32; // ορισμός ακεραίας μεταβλητής n και εγκαινίαση με τιμή = 32 int* nAdress = &n; // ορισμός διεύθυνσης-μεταβλητής (ακεραίου)Μετά την εκτέλεση της τελευταίας εντολής η nAdress περιέχει την διεύθυνση μνήμης του n. Επομένως το περιεχόμενο *nAdress είναι 32.
#include "comx.h"που περιέχει τον ορισμό του interface της κλάσης. Η ίδια διαίρεση ακολουθήται και σε αρχεία συναρτήσεων (βιβλιοθήκες) που χρησιμοποιούν μιά κλάση. Ενδεικτικά κατασκευάζουμε μιά μικρή βιβλιοθήκη με 5 συναρτήσεις. Οι ανακοινώσεις των συναρτήσεων τοποθετούνται σε αρχείο με το όνομα cmxFunctions.h. Τα σώματα των συναρτήσεων τοποθετούνται αντίστοιχα σε αρχείο με το όνομα cmxFunctions.cpp.
Interface, δημιουργούμε αρχείο κειμένου με όνομα cmxFunctions.h το οποίο περιέχει:
#ifndef CMXFUNCTIONS #define CMXFUNCTIONS class cmx; double inner(const cmx & a, const cmx & b ); double det( const cmx & a, const cmx & b); cmx middle(const cmx & a, const cmx & b); cmx rotate( const cmx & a ); cmx power( const cmx & a, int n ); #endif //CMXFUNCTIONS
Impementation, δημιουργούμε αρχείο κειμένου με όνομα cmxFunctions.cpp το οποίο περιέχει:
#include "comx.h" #include "cmxFunctions.h" double inner(const cmx & a, const cmx & b ) // inner product of two complexes { return a.x*b.x + a.y*b.y; } double det( const cmx & a, const cmx & b) { return a.x*b.y-a.y*b.x; } cmx middle(const cmx & a, const cmx & b) { return cmx( 0.5*(a.x+b.x), 0.5*(a.y+b.y) ); } cmx rotate( const cmx & a ) { return cmx( -a.y, a.x ); } cmx power( const cmx & a, int n ) { cmx z, w; int m = n ; if( (a.x == 0.0) && (a.y == 0.0) ) {return a;} if( n==0 ) { w.set(1.0, 0.0); return w; } else if(n<0) { z = cmx(1.0,0.0)/a; m = -n; } else { z = a; } w = z; for( int i=0; i<m-1; i++) { w= w*z; } return w; }
if( (a.x == 0.0) && (a.y == 0.0) ) {return a;} | Το νέο σύμβολο && σημαίνει το λογικό-και. Η εντός του if παρασταση είναι αληθής όταν και το a.x=0 και το a.y=0, δηλαδή όταν ο a είναι ο μηδενικός μιγαδικός. |
z = cmx(1.0,0.0)/a; | Εδώ βάζω z = 1/a. το cmx(1.0,0.0) είναι το μιγαδικό 1 που ορίζεται μέσω ενός κατασκευαστή της cmx. |
for( int i=0; i<m-1; i++) z.print(true); | for-βρόγχος. Εδώ είναι ο ελεγκτής του βρόγχου που καθόρίζει ότι α) i είναι μιά ακέραια μεταβλητή που ξεκινά από την τιμή 0, β) η i αυξάνεται μέχρι το m-2 συμπεριλαμβανομένου. γ) η i αυξάνεται με βήμα 1. Μετά κάθε αύξηση εκτελούνται οι εντολές που περιέχονται στο μπλοκ κάτω από τον ελεγκτή, εφόσον το i ικανοποιεί την μεσαία συνθήκη. |
#include "comx.h" // the interface of cmx class #include "cmxFunctions.h" // the interface of the small library #include <iostream.h> int main(int argc, char* argv[]) { cmx z(2.3, 7.2), w( 3.5, -6.7 ), u( -10.4, -3.1 ), v; cout << "meson toy zw = "; middle(z,w).print(true); cout << "orizousa tvn z, w ="; cout << det(z,w) << endl; cout << "strofi toy u = "; rotate(u).print(true); cout << "esoteriko ginomeno ton z, w = "; cout << inner(z,w) << endl; cout << " z eis tin 3 = " ; power(z,3).print(true); cout << " z eis tin -4 = " ; power(z,-4).print(true); cout << " z eis tin 0 = "; power(z,0).print(true); cout << " 0 eis tin -5 : " ; power(v,-5).print(true); return 0; }