This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision | Previous revision | ||
|
cpp:functions [2021/04/27 06:43] |
cpp:functions [2021/04/27 07:43] gthanos [Υπερφόρτωση συναρτήσεων] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Συναρτήσεις ====== | ||
| + | |||
| + | Στη C++ οι μέθοδοι συνηθίζεται να καλούνται συναρτήσεις. Η συγκεκριμένη ονοματολογία προέρχεται ως κληρονομιά από την γλώσσα C. Η βασική διαφορά σε σχέση με την Java είναι ότι μπορείτε να ορίσετε συναρτήσεις οι οποίες δεν ανήκουν σε κλάσεις, | ||
| + | <code c++> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | |||
| + | int addition (int a, int b) { return a+b; } | ||
| + | |||
| + | int main () { | ||
| + | int x=5; | ||
| + | x = 5 + addition(8, | ||
| + | cout << "x: " << x << endl; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Ορίσματα και επιστρεφόμενη τιμή της συνάρτησης main ===== | ||
| + | |||
| + | Γνωρίζετε από τη C ότι η συνάρτηση //main// από την οποία εκκινεί το πρόγραμμα ορίζεται ως εξής: | ||
| + | <code c++> | ||
| + | int main(int argc, char *argv[]); | ||
| + | </ | ||
| + | |||
| + | Σε ένα πρόγραμμα C++ η main μπορεί να δηλωθεί χωρίς να λαμβάνει κανένα όρισμα, | ||
| + | <code c++> | ||
| + | int main(); | ||
| + | </ | ||
| + | |||
| + | Επίσης, | ||
| + | ===== Προκαθορισμένες τιμές παραμέτρων (default values) ===== | ||
| + | |||
| + | Κατά τον ορισμό μίας συνάρτησης είναι δυνατόν να ορίσετε προκαθορισμένες τιμές για συγκεκριμένες παραμέτρους. Με αυτό τον τρόπο η ίδια μέθοδος μπορεί να κληθεί με λιγότερα ορίσματα, | ||
| + | |||
| + | <code c++ power_of.cpp> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | |||
| + | int powerOf(int base, int e=2) { | ||
| + | if(e==0) | ||
| + | return 1; | ||
| + | int result = base; | ||
| + | for(int i=1; i<e; i++) { | ||
| + | result *= base; | ||
| + | } | ||
| + | return result; | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | int a = 2, b; | ||
| + | b = powerOf(a); | ||
| + | cout << "a: " << a <<", | ||
| + | b = powerOf(a, 3); | ||
| + | cout << "a: " << a <<", | ||
| + | b = powerOf(a, 5); | ||
| + | cout << "a: " << a <<", | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Inline συναρτήσεις ===== | ||
| + | |||
| + | Κάθε φορά που καλείται μια συνάρτηση συνεπάγεται μία μικρή καθυστέρηση προκειμένου να αποθηκευτούν οι παράμετροι κλήσης της συνάρτησης στη στοίβα και να αποθηκευθεί η επιστρεφόμενη τιμή σε μία μεταβλητή. Για μικρές σε έκταση συναρτήσεις που καλούνται συχνά το συγκεκριμένο κόστος μπορεί να μην είναι αμελητέο σε σχέση με τον συνολικό χρόνο εκτέλεσης τους. | ||
| + | |||
| + | Μπορείτε να αποφύγετε την κλήση μίας συνάρτησης δηλώνοντας τη ως //inline//. Σε αυτή την περίπτωση δεν γίνεται καμία κλήση συνάρτησης, | ||
| + | |||
| + | <code c++ inline.cpp> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | inline int add(int a, int b) { return a+b;} | ||
| + | int main() { | ||
| + | int sum = 0; | ||
| + | for(int i=1; i<=100; i++) { | ||
| + | sum = add(sum,i); | ||
| + | cout << i << " | ||
| + | } | ||
| + | cout << "sum: " << sum << endl; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <WRAP tip 80% center round> | ||
| + | Ο παραπάνω κώδικας δηλώνει τη σύσταση του προγραμματιστή προς τον μεταγλωττιστή ο κώδικας της συνάρτησης //add// να ενσωματωθεί στον κώδικα που την καλεί. Σημειώστε ότι ο μεταγλωττιστής μπορεί να επιλέξει να ενσωματώσει μία συνάρτηση στον κώδικα που την καλεί ακόμη και εάν δεν έχει δηλωθεί //inline//. Αντίστοιχα, | ||
| + | </ | ||
| + | |||
| + | ===== Κλήση με τιμή και κλήση με αναφορά ===== | ||
| + | |||
| + | Κατά την κλήση μίας συνάρτησης οι παράμετροι της συνάρτησης αντιγράφονται στο //stack// πριν από την εκτέλεσης της. Μετά την ολοκλήρωση εκτέλεσης οι παράμετροι διαγράφονται από το //stack// και οποιεσδήποτε αλλαγές έγιναν στις παραμέτρους κατά τη κλήσης της συνάρτησης είναι αδύνατο να διατηρηθούν μετά την κλήση της. | ||
| + | |||
| + | Εάν θέλουμε οι αλλαγές στα ορίσματα της συνάρτησης να διατηρηθούν και μετά την κλήση της θα πρέπει να περάσουμε τις διευθύνσεις των εμπλεκόμενων μεταβλητών και όχι τις μεταβλητές αυτές καθ' | ||
| + | |||
| + | <code c++ powerOf2.cpp> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | |||
| + | int powerOf2(int x) { | ||
| + | x = x*x; | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | int powerOf2Ref(int &x) { | ||
| + | x = x*x; | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | int powerOf2Ptr(int *x) { | ||
| + | *x = (*x)*(*x); | ||
| + | return *x; | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | int a = 5, b; | ||
| + | b = powerOf2(a); | ||
| + | cout << "a: " << a <<", | ||
| + | a = 5; | ||
| + | b = powerOf2Ref(a); | ||
| + | cout << "a: " << a <<", | ||
| + | a = 5; | ||
| + | b = powerOf2Ptr(& | ||
| + | cout << "a: " << a <<", | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Το αποτέλεσμα της εκτέλεσης του παραπάνω προγράμματος έχει ως εξής: | ||
| + | < | ||
| + | a: 5, b: 25 | ||
| + | a: 25, b: 25 | ||
| + | a: 25, b: 25 | ||
| + | </ | ||
| + | |||
| + | Παρατηρήστε ότι μετά την έξοδο από τις μεθόδους // | ||
| + | |||
| + | <WRAP center round tip 80%> | ||
| + | Κατά την κλήση μίας συνάρτησης, | ||
| + | |||
| + | Για τους βασικούς τύπους δεδομένων η κλήση με αναφορά σε σχέση με την κλήση με τιμή δεν βελτιώνει την ταχύτητα εκτέλεσης του προγράμματος. | ||
| + | </ | ||
| + | |||
| + | ===== Αναφορές ως επιστρεφόμενες τιμές συναρτήσεων ===== | ||
| + | |||
| + | [[cpp: | ||
| + | |||
| + | ===== Υπερφόρτωση συναρτήσεων ===== | ||
| + | |||
| + | Η C++ (όπως και η Java) επιτρέπει δύο συναρτήσεις να έχουν το ίδιο όνομα αλλά διαφορετικό αριθμό ή τύπο παραμέτρων. Αυτό συμβαίνει διότι η συνάρτηση δεν ορίζεται μόνο από το όνομα της, αλλά από το όνομα της σε συνδυασμό με τις τυπικές παραμέτρους που λαμβάνει. Δείτε το προηγούμενο παράδειγμα προσαρμοσμένο, | ||
| + | |||
| + | <code c++ powerOf2.cpp> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | |||
| + | int powerOf2(int &x) { | ||
| + | x = x*x; | ||
| + | return x; | ||
| + | } | ||
| + | |||
| + | int powerOf2(int *x) { | ||
| + | *x = (*x)*(*x); | ||
| + | return *x; | ||
| + | } | ||
| + | |||
| + | double powerOf2(double *x) { | ||
| + | *x = (*x)*(*x); | ||
| + | return *x; | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | int a = 5, b; | ||
| + | double d = 5.0, e; | ||
| + | b = powerOf2(a); | ||
| + | cout << "a: " << a <<", | ||
| + | a = 5; | ||
| + | b = powerOf2(& | ||
| + | cout << "a: " << a <<", | ||
| + | e = powerOf2(& | ||
| + | cout << "d: " << d <<", | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Template συναρτήσεων ===== | ||
| + | |||
| + | Υπερφορτωμένες συναρτήσεις συχνά έχουν τον ίδιο αριθμό και τύπο ορισμάτων, | ||
| + | <code c++> | ||
| + | int sum (int a, int b) { return a+b; } | ||
| + | double sum (double a, double b) { return a+b; } | ||
| + | </ | ||
| + | |||
| + | Παρατηρούμε ότι οι παραπάνω συναρτήσεις έχουν τον ίδιο αριθμό παραμέτρων και το ίδιο σώμα, αλλά διαφορετικούς τύπους παραμέτρων. Σε αυτές τις περιπτώσεις η C++ δίνει τη δυνατότητα ορισμού template συναρτήσεων, | ||
| + | |||
| + | <code c++> | ||
| + | template <class T> | ||
| + | T sum (T a, T b) { | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | η δεσμευμένη έκφραση '' | ||
| + | |||
| + | <code c++> | ||
| + | int s = sum< | ||
| + | </ | ||
| + | |||
| + | Δείτε το παραπάνω παράδειγμα που περιέχει επιμέρους κλήσεις για τη μέθοδο sum. | ||
| + | |||
| + | <code cpp sumUsage.cpp> | ||
| + | #include < | ||
| + | using namespace std; | ||
| + | |||
| + | template < | ||
| + | T sum (T a, T b) { | ||
| + | return a+b; | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | cout << "10 + 20 = " << sum< | ||
| + | cout << "10.5 + 20.5 = " << sum< | ||
| + | cout << "1.5 + 2 = " << sum<> | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <WRAP center round tip 80%> | ||
| + | Παρατηρήστε ότι κατά την τελευταία κλήση ο // | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||