class cmx { public: double x; double y; public: cmx(); cmx( const cmx & other ); // very important copy-constructor cmx( const double & xx, const double & yy ); ~cmx(); 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 ); };
public: double x; double y; | Οι δύο μεταβλητές της κλάσης: δύο πραγματικοί αριθμοί διπλής ακρίβειας (double) προορισμένοι να κρατούν το πραγματικό και φανταστικό μέρος ενός μιγαδικού αριθμού. |
cmx(); | Ο βασικός κατασκευαστής (default constructor) της κλάσης. |
cmx( const cmx & other ); |
Ένας άλλος πολύ σημαντικός κατασκευαστής, κατασκευαστής-αντιγραφής,
(copy-constructor) δημιουργεί αντίγραφο ενός μιγαδικού. Σημείωσε
την const που καθορίζει ότι η τιμή της μεταβλητής που ακολουθεί
μπορεί να χρησιμοποιηθεί από την συνάρτηση γιά τους σκοπούς της αλλά
δεν επιτρέπεται να αλλοιωθεί η τρέχουσα τιμή της. Σημείωσε ακόμη την & που συμβολίζει την διεύθυνση όπου είναι αποθηκευμένη η μεταβλητή που ακολουθεί (και όχι την πραγματική τιμή της). |
cmx( const double & xx, const double & yy ); |
Ενας τρίτος κατασκευαστής που φτιάχνει τον μιγαδικό από το πραγματικό
και φανταστικό μέρος του. Σημείωσε πάλι τα const και & . Υπό κανονικές συνθήκες μιά συνάρτηση f(x,y, ...) κάνει αντίγραφα των x, y, ... μέσα στην μνήμη και δουλεύει με τα αντίγραφα. Το & υποχρεώνει την f να δουλέψει με τα ίδια τα αντικείμενα που συμβολίζουν τα x, y, ... και έτσι να γλυτώσει τον χρόνο της αντιγραφής. |
~cmx(); | Ο γνωστός μας καταστροφέας, και σ΄αυτήν την κλάση δεν κάνει τίποτε. |
void set(const double & xx, const double & yy); | Μιά συνάρτηση που θέτει τις τιμές πραγματικού/φανταστικού μέρους του μιγαδικού. |
void setPol(const double & r, const double & angle); | Μιά συνάρτηση που ορίζει τον μιγαδικό από τις πολικές συντεταγμένες του. |
double re() const; double im() const; | Δύο απλές συναρτήσεις που επιστρέφουν αντίστοιχα πραγματικό/φανταστικό μέρος του μιγαδικού. Σημείωσε πάλι το const , αυτή την φορά στο τέλος της συνάρτησης. Αυτό απαγορεύει στην συνάρτηση-μέλος της κλάσης να αλλάξη την τιμή των μεταβλητών της. |
cmx syz() const; double norm() const; double argm() const; | Τρεις απλές συναρτήσεις που επιστρέφουν αντίστοιχα τον συζυγή, το μέτρο και το όρισμα ενός μιγαδικού. |
void print( bool line = false) const; | Μιά συνάρτηση που τυπώνει τον μιγαδικό και αλλάζει γραμμή όταν η λογική μεταβλητή έχει τιμή true. Το =false σημαίνει ότι αν καλέσουμε την συνάρτηση γράφοντας print() τούτο ισοδυναμεί με print(false). |
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 που είναι μπροστά τους. Οι φίλες συναρτήσεις χαρακτηρίζονται από το ότι έχουν πρόσβαση στις μεταβλητές της κλάσης. Εδώ τις χρησιμοποιούμε για να ορίσουμε τις πράξεις + , - , * γιά μιγαδικούς. Οι φίλες συναρτήσεις δεν είναι συναρτήσεις μέλη της κλάσης. Δεν μπορούμε να αναφερθούμε σ΄αυτές με την γνωστή τελεία, γράφοντας z.f(...) όπως κάνουμε με τις συναρτήσεις μέλη.
// constructors (may have many) cmx::cmx(){x=y=0.0;} cmx::cmx( const cmx & other ):x(other.x), y(other.y){} cmx::cmx( const double & xx, const double & yy ):x(xx),y(yy) {} // destructor (only one) cmx::~cmx(){} // set-get functions void cmx::set( const double & xx, const double & yy) { x = xx; y=yy; } void cmx::setPol( const double & r, const double & angle) { x = r*cos(angle); y = r*sin(angle); } double cmx::re() const {return x; } double cmx::im() const {return y; } // some functions cmx cmx::syz() const // conjugate complex { cmx z; z.x=x; z.y=-y; return z; } double cmx::norm() const // norm of a complex { double q ( x*x + y*y ); return sqrt(q); } double cmx::argm() const // argument of a complex { return atan2(y,x); } void cmx::print( bool line) const // print a complex { cout << " ( " << x <<" , " << y << " ) " ; if(line) cout << endl; // change line } cmx operator+( const cmx & a, const cmx & b ) { cmx z; z.x = a.x + b.x; z.y = a.y + b.y; return z; } cmx operator-( const cmx & a, const cmx & b ) { cmx z; z.x = a.x - b.x; z.y = a.y - b.y; return z; } cmx operator*( const cmx & a, const cmx & b ) { cmx z; z.x = a.x *b.x - a.y*b.y; z.y = a.x * b.y + a.y*b.x; return z; }
Βλέπουμε ότι στην υλοποίηση ορίζεται το σώμα των συναρτήσεων (member functions) της κλάσης καθώς και οι φίλες συναρτήσεις της κλάσης. Η C++ αναγνωρίζει ότι πρόκειται για μέλη της κλάσης cmx από την προσθήκη του cmx:: μπροστά από κάθε συνάρτηση. Όπως ανέφερα παραπάνω οι φίλες συναρτήσεις, που ορίζουν τις βασικές πράξεις με μιγαδικούς, δεν είναι συναρτήσεις μέλη της κλάσης, γι΄αυτό δεν έχουν το cmx:: μπροστά τους.
#include "comx.h"που περιέχει τον ορισμό του interface της κλάσης. Γιά την κλάση cmx θα δημιουργούσαμε λοιπόν τα δυο παρακάτω αρχεία:
Interface, δημιουργούμε αρχείο κειμένου με όνομα comx.h το οποίο περιέχει:
#ifndef CMXCLASS /* class cmx interface */ #define CMXCLASS class cmx { public: double x; double y; public: cmx(); cmx( const cmx & other ); // very important copy-constructor cmx( const double & xx, const double & yy ); ~cmx(); 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 ); }; #endif // CMXCLASS
Impementation, δημιουργούμε αρχείο κειμένου με όνομα comx.cpp το οποίο περιέχει:
#include <iostream.h> // class cmx implementing complex numbers #include <math.h> // to achieve greater precision use double #include "comx.h" // the interface of cmx class // constructors (may have many) cmx::cmx(){x=y=0.0;} cmx::cmx( const cmx & other ):x(other.x), y(other.y){} cmx::cmx( const double & xx, const double & yy ):x(xx),y(yy) {} // destructor (only one doing nothing) cmx::~cmx(){} // set-get functions void cmx::set( const double & xx, const double & yy) { x = xx; y=yy; } void cmx::setPol( const double & r, const double & angle) { x = r*cos(angle); y = r*sin(angle); } double cmx::re() const {return x; } double cmx::im() const {return y; } // some functions cmx cmx::syz() const // conjugate complex { cmx z; z.x=x; z.y=-y; return z; } double cmx::norm() const // norm of a complex { double q ( x*x + y*y ); return sqrt(q); } double cmx::argm() const // argument of a complex { return atan2(y,x); } void cmx::print( bool line) const // print a complex { cout << " ( " << x <<" , " << y << " ) " ; if(line) cout << endl; // change line } cmx operator+( const cmx & a, const cmx & b ) { cmx z; z.x = a.x + b.x; z.y = a.y + b.y; return z; } cmx operator-( const cmx & a, const cmx & b ) { cmx z; z.x = a.x - b.x; z.y = a.y - b.y; return z; } cmx operator*( const cmx & a, const cmx & b ) { cmx z; z.x = a.x *b.x - a.y*b.y; z.y = a.x * b.y + a.y*b.x; return z; }
#include <iostream.h> #include "comx.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 << "z ="; z.print(true); cout << "w ="; w.print(true); cout << "u ="; u.print(true); cout << "v ="; v.print(true); cout << " conj of z " ; z.syz().print(true); v = z+w; cout << " sum z+w = " ; v.print(true); v = z*w; cout << " product z*w = "; v.print(true); v.setPol( 3., 1.2 ); cout << " v in cartesian : " ; v.print(true); cout << " norm and argument = " << endl; cout << v.norm() << endl; cout << v.argm() << endl; return 0; }
#include <iostream.h> #include "comx.h" | Η πρώτη γνωστή και από προηγούμενα προγράμματα συνδέει με την βασική βιβλιοθήκη εισόδου-εξόδου δεδομένων. Η δεύτερη εντολή συνδέει με την κλάση cmx. |
cmx z(2.3, 7.2), w( 3.5, -6.7 ), u( -10.4, -3.1 ), v; | Ορισμός 4 μεταβλητών τύπου cmx, στις τρείς από τις οποίες δίδονται και αρχικές τιμές. Η C++ χρησιμοποιεί γιά τις 3 πρώτες τον 3ο κατασκευαστή. Γιά την τελευταία v χρησιμοποιεί τον πρώτο κατασκευαστή (βασικό). |
cout << "z ="; z.print(true); | Το ζεύγος εντολών εδώ τυπώνει z = ( 2.3 , 7.2 ) και αλλάζει γραμμή (λόγω του true στην z.print(true)). Ανάλογα και τα υπόλοιπα τρία ζεύγη εντολών τυπώνουν τους μιγαδικούς που ορίστηκαν στην αρχική γραμμή. |
cout << " conj of z " ; z.syz().print(true); | Ενδιαφέρον εδώ έχει η σύνθετη εντολή z.syz().print(true); που τυπώνει τον συζυγή του z. Σημείωσε εδώ ότι πρώτα εκτελείται η z.syz() της οποίας το αποτέλεσμα είναι πάλι τύπου cmx και επομένως έχει νόημα η z.syz().print(true);. |
v = z+w; | Σ αυτήν την μικρή εντολή κρύβεται λίγη από την γοητεία της C++. Προσθέτουμε μιγαδικούς με το σύμβολο που έχουμε συνηθίσει! Το νόημα του συμβόλου καθορίζει η φίλτατη συνάρτηση operator+(...). Σημείωσε ότι η εντολή αυτή είναι ισοδύναμη με την v = operator+(z,w); . |
cout << " sum z+w = " ; v.print(true); | Ζεύγος εντολών που τυπώνουν sum z+w = ( 5.8 , 0.5 ) και αλλάζουν γραμμή. |
v = z*w; cout << " product z*w = "; v.print(true); | Και εδώ η πρώτη με το * βρίσκει το γινόμενο και οι δύο άλλες τυπώνουν το αποτέλεσμα. Η πρώτη εντολή είναι πάλι ισοδύναμη με την v = operator*(z,w); . |
v.setPol( 3., 1.2 ); | Υπολογίζει τον μιγαδικό από τις πολικές συντεταγμένες του (z = 3(cos(1.2)+isin(1.2)). Οι υπόλοιπες εντολές τυπώνουν τις συντετγαμένες του z και ξαναβρίσκουν απ΄ αυτές το μέτρο και το όρισμα του z, που φυσικά συμπίπτουν με τα αρχικά 3 και 1.2. |