cpp:functions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
cpp:functions [2017/04/11 09:13]
gthanos [Template functions]
cpp:functions [2021/04/27 07:29]
gthanos [Κλήση με τιμή και κλήση με αναφορά]
Line 1: Line 1:
-====== Συναρτήσεις ή μέθοδοι ======+====== Συναρτήσεις ======
  
 Στη C++ οι μέθοδοι συνηθίζεται να καλούνται συναρτήσεις. Η συγκεκριμένη ονοματολογία προέρχεται ως κληρονομιά από την γλώσσα C. Η βασική διαφορά σε σχέση με την Java είναι ότι μπορείτε να ορίσετε συναρτήσεις οι οποίες δεν ανήκουν σε κλάσεις, όπως παρακάτω. Στη C++ οι μέθοδοι συνηθίζεται να καλούνται συναρτήσεις. Η συγκεκριμένη ονοματολογία προέρχεται ως κληρονομιά από την γλώσσα C. Η βασική διαφορά σε σχέση με την Java είναι ότι μπορείτε να ορίσετε συναρτήσεις οι οποίες δεν ανήκουν σε κλάσεις, όπως παρακάτω.
Line 15: Line 15:
 </code> </code>
  
-====== Η επιστρεφόμενη τιμή της συνάρτησης main ======+===== Ορίσματα και επιστρεφόμενη τιμή της συνάρτησης main ===== 
 + 
 +Γνωρίζετε από τη C ότι η συνάρτηση //main// από την οποία εκκινεί το πρόγραμμα ορίζεται ως εξής: 
 +<code c++> 
 +int main(int argc, char *argv[]); 
 +</code> 
 + 
 +Σε ένα πρόγραμμα C++ η main μπορεί να δηλωθεί χωρίς να λαμβάνει κανένα όρισμα, όπως παρακάτω 
 +<code c++> 
 +int main(); 
 +</code> 
 + 
 +Επίσης, δεν είναι απαραίτητο να δηλώσετε επιστρεφόμενη τιμή στη //main//. Εάν δεν το κάνετε ο μεταγλωττιστής ορίζει ως επιστρεφόμενη τιμή το 0. Ένα πρόγραμμα που επιστρέφει 0 εκλαμβάνεται από το σύστημα ότι αυτό εκτελέστηκε με επιτυχία. 
 +===== Προκαθορισμένες τιμές παραμέτρων (default values) ===== 
 + 
 +Κατά τον ορισμό μίας συνάρτησης είναι δυνατόν να ορίσετε προκαθορισμένες τιμές για συγκεκριμένες παραμέτρους. Με αυτό τον τρόπο η ίδια μέθοδος μπορεί να κληθεί με λιγότερα ορίσματα, τόσα όσα και οι παράμετροι που έχουν προκαθορισμένες τιμές. Στο παρακάτω παράδειγμα, η μέθοδος powerOf ορίζεται ώστε ο εκθέτης ύψωσης σε δύναμη να έχει την προκαθορισμένη τιμή 2. Στη συνέχει καλείται η συνάρτηση με ένα ή δύο ορίσματα. 
 + 
 +<code c++ power_of.cpp> 
 +#include <iostream> 
 +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: " << b << endl; 
 +  b powerOf(a, 3); 
 +  cout << "a: " << a <<", b: " << b << endl; 
 +  b powerOf(a, 5); 
 +  cout << "a: " << a <<", b: " << b << endl; 
 +
 +</code> 
 + 
 +===== Inline συναρτήσεις ===== 
 + 
 +Κάθε φορά που καλείται μια συνάρτηση συνεπάγεται μία μικρή καθυστέρηση προκειμένου να αποθηκευτούν οι παράμετροι κλήσης της συνάρτησης στη στοίβα και να αποθηκευθεί η επιστρεφόμενη τιμή σε μία μεταβλητή. Για μικρές σε έκταση συναρτήσεις που καλούνται συχνά το συγκεκριμένο κόστος μπορεί να μην είναι αμελητέο σε σχέση με τον συνολικό χρόνο εκτέλεσης τους. 
 + 
 +Μπορείτε να αποφύγετε την κλήση μίας συνάρτησης δηλώνοντας τη ως //inline//. Σε αυτή την περίπτωση δεν γίνεται καμία κλήση συνάρτησης, αλλά ο κώδικας της "καλούμενης" συνάρτησης ενσωματώνεται μέσα στον κώδικα που την καλεί. Σημειώστε ότι σε αυτή την περίπτωση θα έχετε τόσα αντίγραφα της συνάρτησης όσα και τα σημεία στον κώδικα που αυτή καλείται. Παρακάτω δίνεται το παράδειγμα της συνάρτησης //add// που δηλώνεται ως //inline//
 + 
 +<code c++ inline.cpp> 
 +#include <iostream> 
 +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 << "  " << sum << endl; 
 +  } 
 +  cout << "sum: " << sum << endl; 
 +
 +</code> 
 + 
 +<WRAP tip 80% center round> 
 +Ο παραπάνω κώδικας δηλώνει τη σύσταση του προγραμματιστή προς τον μεταγλωττιστή ο κώδικας της συνάρτησης //add// να ενσωματωθεί στον κώδικα που την καλεί. Σημειώστε ότι ο μεταγλωττιστής μπορεί να επιλέξει να ενσωματώσει μία συνάρτηση στον κώδικα που την καλεί ακόμη και εάν δεν έχει δηλωθεί //inline//. Αντίστοιχα, είναι πιθανόν να μην ενσωματώσει μία συνάρτηση ακόμη και εάν είναι δηλωμένη //inline//. Η παραπάνω δήλωση δεν είναι δεσμευτική για τον μεταγλωττιστή. 
 +</WRAP>
  
 ===== Κλήση με τιμή και κλήση με αναφορά ===== ===== Κλήση με τιμή και κλήση με αναφορά =====
  
-Κατά την κλήση μίας συνάρτησης οι παράμετροι της συνάρτησης αντιγράφονται στο stack πριν από την εκτέλεσης της. Μετά την ολοκλήρωση εκτέλεσης οι παράμετροι διαγράφονται από το stack και οποιαδηποτε αλλαγές έγιναν στις παραμέτρους κατά τη κλήσης της συνάρτησης είναι αδύνατο να διατηρηθούν μετά την κλήση της+Κατά την κλήση μίας συνάρτησης οι παράμετροι της συνάρτησης αντιγράφονται στο //stack// πριν από την εκτέλεσης της. Μετά την ολοκλήρωση εκτέλεσης οι παράμετροι διαγράφονται από το //stack// και οποιεσδήποτε αλλαγές έγιναν στις παραμέτρους κατά τη κλήσης της συνάρτησης είναι αδύνατο να διατηρηθούν μετά την κλήση της.
  
-Εάν θέλουμε οι αλλαγές στα ορίσματα της συνάρτησης να διατηρηθούν και μετά την κλήση της θα πρέπει να περάσουμε τις διευθύνσεις των εμπλεκόμενων μεταβλητών και όχι τις μεταβλητές αυτές καθ' αυτές. Σε αυτή την περίπτωση αντιγράφονται οι διευθύνσεις στο //stack// και όχι οι τιμές. Οι αλλαγές στις τιμές διατηρούνται ακόμη και μετά την έξοδο από τη συνάρτηση. Δείτε το παρακάτω παράδειγμα που αποτυπώνει τις συγκεκριμένες διαφορές.+Εάν θέλουμε οι αλλαγές στα ορίσματα της συνάρτησης να διατηρηθούν και μετά την κλήση της θα πρέπει να περάσουμε τις διευθύνσεις των εμπλεκόμενων μεταβλητών και όχι τις μεταβλητές αυτές καθ' αυτές. Σε αυτή την περίπτωση αντιγράφονται οι διευθύνσεις των μεταβλητών στο //stack// και όχι οι τιμές τους. Οι διευθύνσεις που αντιγράφονται καταστρέφονται μετά την ολοκλήρωση κλήσης της συνάρτησης, όμως οι αλλαγές στις τιμές των μεταβλητών διατηρούνται και μετά την έξοδο από τη συνάρτηση. Δείτε το παρακάτω παράδειγμα που αποτυπώνει τις συγκεκριμένες διαφορές.
  
 <code c++ powerOf2.cpp> <code c++ powerOf2.cpp>
Line 63: Line 127:
  
 Παρατηρήστε ότι μετά την έξοδο από τις μεθόδους //powerOf2Ref// και //powerOf2Ptr// η μεταβλητή ''a'' έχει αλλάξει τιμή κάτι που δεν ισχύει μετά την έξοδο από την //powerOf2//. Παρατηρήστε ότι μετά την έξοδο από τις μεθόδους //powerOf2Ref// και //powerOf2Ptr// η μεταβλητή ''a'' έχει αλλάξει τιμή κάτι που δεν ισχύει μετά την έξοδο από την //powerOf2//.
 +
 +<WRAP center round info 80%>
 +Κατά την κλήση μίας συνάρτησης, όταν θέλουμε να περάσουμε αντικείμενα που περιέχουν μεγάλο όγκο πληροφορίας είναι προτιμότερο να τα περάσουμε με αναφορά ακόμη και εάν δεν επιθυμούμε οι πιθανές αλλαγές στις τυπικές παραμέτρους να είναι ορατές μετά την κλήση της συνάρτησης. Ο λόγος είναι ότι η κλήση με αναφορά έχει σταθερό κόστος αντιγραφής ισοδύναμο με το μήκος μίας διεύθυνσης μνήμης, ενώ η αντιγραφή ενός μεγάλου αντικειμένου έχει κόστος όσο το μέγεθος του αντικειμένου. 
 +
 +Για τους βασικούς τύπους δεδομένων η κλήση με αναφορά σε σχέση με την κλήση με τιμή δεν βελτιώνει την ταχύτητα εκτέλεσης του προγράμματος.
 +</WRAP>
  
 ===== Υπερφόρτωση συναρτήσεων ===== ===== Υπερφόρτωση συναρτήσεων =====
Line 100: Line 170:
 </code> </code>
  
-Παρατηρήστε ότι οι συνάρτηση //powerOf2// έχει τρεις διαφορετικές εκδόσεις: μία που λαμβάνει αναφορά σε ακέραιο, μία που λαμβάνει δείκτη σε ακέραιο και μία που λαμβάνει δείκτη σε //double//. Η διάκριση μεταξύ συναρτήσεων με το ίδιο όνομα γίνεται με βάση τη σειρά και τον τύπο των τυπικών παραμέτρων τους. 
  
-<WRAP center round info 80%> 
-Όταν θέλουμε να περάσουμε σε μία συνάρτηση μεγάλα αντικείμενα που περιέχουν πολύ πληροφορία είναι προτιμότερο να τα περάσουμε με αναφορά ακόμη και εάν δεν επιθυμούμε οι πιθανές αλλαγές στις τυπικές παραμέτρους να είναι ορατές μετά την κλήση της συνάρτησης. Ο λόγος είναι ότι η κλήση με αναφορά έχει σταθερό κόστος αντιγραφής ισοδύναμο με το μήκος μίας διεύθυνσης μνήμης, ενώ η αντιγραφή ενός μεγάλου αντικειμένου έχει κόστος όσο το μέγεθος του αντικειμένου.  
  
-Για βασικούς τύπους δεδομένων η κλήση με αναφορά δεν έχει καμία επίπτωση στην ταχύτητα εκτέλεσης του προγράμματος. +===== Template συναρτήσεων =====
-</WRAP>+
  
-===== Προκαθορισμένες τιμές παραμέτρων (default values=====+Υπερφορτωμένες συναρτήσεις συχνά έχουν τον ίδιο αριθμό και τύπο ορισμάτων, όπως παρακάτω 
 +<code c++> 
 +int sum (int a, int b) { return a+b; } 
 +double sum (double a, double b{ return a+b; } 
 +</code>
  
-Κατά τον ορισμό μίας συνάρτησης είναι δυνατόν να ορίσετε προκαθορισμένες τιμές για συγκεκριμένες παραμέτρους. Με αυτό τον τρόπο η ίδια μέθοδος μπορεί να κληθεί με λιγότερα ορίσματα, τόσα όσα και οι παράμετροι που έχουν προκαθορισμένες τιμές. Στο παρακάτω παράδειγμα, η μέθοδος powerOf ορίζεται ώστε ο εκθέτης ύψωσης σε δύναμη να έχει την προκαθορισμένη τιμή 2. Στη συνέχει καλείται η συνάρτηση με ένα ή δύο ορίσματα.+Παρατηρούμε ότι οι παραπάνω συναρτήσεις έχουν το ίδιο διαφορετικούς τύπου παραμέτρων, αλλά τον ίδιο αριθμό παραμέτρων και το ίδιο σώμα. Σε αυτές τις περιπτώσεις η C++ δίνει τη δυνατότητα ορισμού template συναρτήσεων ως εξής:
  
-<code c++ powerOf.cpp>+<code c++
 +template <class T> 
 +T sum (T a, T b) { 
 +  return a+b; 
 +
 +</code> 
 + 
 +η δεσμευμένη έκφραση ''template <class T>'') μπορεί να αντικατασταθεί από την επίσης δεσμευμένη έκφραση ''template <typename T>''. Προκειμένου να κάνετε χρήση ενός template συνάρτησης θα πρέπει κατά την κλήση να ορίσετε και τον τύπο των δεδομένων για τον οποίο καλείται τη συγκεκριμένη συνάρτηση ως εξής: 
 + 
 +<code c++> 
 +int s = sum<int>(5,10); 
 +</code> 
 + 
 +Δείτε το παραπάνω παράδειγμα που περιέχει επιμέρους κλήσεις για τη μέθοδο sum. 
 + 
 +<code cpp sumUsage.cpp>
 #include <iostream> #include <iostream>
 using namespace std; using namespace std;
  
-int powerOf(int baseint e=2) { +template <typename T> 
-  if(e==0) +T sum (T aT b) { 
-    return 1; +  return a+b;
-  for(int i=1; i<e; i++) { +
-    base = base * base; +
-  } +
-  return base;+
 } }
  
 int main() { int main() {
-  int a = 5, b; +  cout << "10 + 20 = " << sum<int>(10,20) << endl;             // sum<int> 
-  b = powerOf(a); +  cout << "10.5 + 20.5 " << sum<double>(10.5,20.5<< endl // sum<double> 
-  cout << "a: " << a <<"b: " << b << endl; +  cout << "1.5 + 2 = " << sum<>(1.5,2.0) << endl;              // compiler deducts sum<double>
-  powerOf(a,3); +
-  cout << "a: " << <<"b: " << b << endl;+
 } }
 </code> </code>
  
-===== Template functions ===== +<WRAP center round tip 80%> 
- +Παρατηρήστε ότι κατά την τελευταία κλήση ο //compiler// έχει την δυνατότητα να εξάγει τον τύπο **T** από τον τύπο των παραμέτρων με τις οποίες καλείται η μέθοδος. 
-Υπερφορτωμένες συναρτήσεις συχνά έχουν τον ίδιο αριθμό και τύπο ορισμάτων, όπως παρακάτω +</WRAP>
- +
-<code c++> +
-int sum (int a, int b) { return a+b; } +
-double sum (double a, double b) { return a+b; } +
-</code> +
  
  
cpp/functions.txt · Last modified: 2021/04/27 06:43 (external edit)