Σημείωση: Οι απαντήσεις δόθηκαν με μια συγκεκριμένη σειρά, αλλά επειδή πολλοί χρήστες ταξινομούν τις απαντήσεις σύμφωνα με τις ψήφους και όχι σύμφωνα με τον χρόνο που δόθηκαν, εδώ είναι ένα ευρετήριο των απαντήσεων με τη σειρά με την οποία έχουν το μεγαλύτερο νόημα:
<sub>, _(Σημείωση: Αυτό προορίζεται να είναι μια καταχώρηση στο Stack Overflow's C++ FAQ. Αν θέλετε να ασκήσετε κριτική στην ιδέα της παροχής μιας FAQ με αυτή τη μορφή, τότε η δημοσίευση στο meta που ξεκίνησε όλα αυτά θα ήταν το κατάλληλο μέρος για να το κάνετε. Οι απαντήσεις σε αυτό το ερώτημα παρακολουθούνται στο C++ chatroom, όπου ξεκίνησε αρχικά η ιδέα των FAQ, οπότε η απάντησή σας είναι πολύ πιθανό να διαβαστεί από αυτούς που είχαν την ιδέα). </sub>,
Το μεγαλύτερο μέρος της εργασίας στην υπερφόρτωση των τελεστών είναι κώδικας που χρησιμοποιείται για την επεξεργασία. Αυτό δεν είναι καθόλου περίεργο, αφού οι τελεστές είναι απλώς συντακτική ζάχαρη, η πραγματική τους εργασία θα μπορούσε να γίνει από (και συχνά προωθείται σε) απλές συναρτήσεις. Αλλά είναι σημαντικό να κάνετε αυτόν τον κώδικα boiler-plate σωστά. Αν αποτύχετε, είτε ο κώδικας του τελεστή σας δεν θα μεταγλωττιστεί είτε ο κώδικας των χρηστών σας δεν θα μεταγλωττιστεί είτε ο κώδικας των χρηστών σας θα συμπεριφερθεί εκπληκτικά.
Υπάρχουν πολλά που μπορούν να ειπωθούν για την ανάθεση. Ωστόσο, τα περισσότερα από αυτά έχουν ήδη ειπωθεί στο GMan's famous Copy-And-Swap FAQ, οπότε'θα παραλείψω τα περισσότερα από αυτά εδώ, παραθέτοντας μόνο τον τέλειο τελεστή ανάθεσης για αναφορά:
X& X::operator=(X rhs)
{
swap(rhs);
return *this;
}
Οι τελεστές bitshift <<
και >>
, αν και εξακολουθούν να χρησιμοποιούνται στη διασύνδεση υλικού για τις λειτουργίες χειρισμού bit που κληρονομούν από τη C, έχουν επικρατήσει περισσότερο ως υπερφορτωμένοι τελεστές εισόδου και εξόδου ροής στις περισσότερες εφαρμογές. Για την καθοδήγηση υπερφόρτωσης ως τελεστές χειρισμού bit, δείτε την παρακάτω ενότητα για τους δυαδικούς αριθμητικούς τελεστές. Για την υλοποίηση της δικής σας προσαρμοσμένης λογικής μορφοποίησης και ανάλυσης όταν το αντικείμενό σας χρησιμοποιείται με iostreams, συνεχίστε.
Οι τελεστές ροής, από τους πιο συχνά υπερφορτωμένους τελεστές, είναι δυαδικοί τελεστές infix για τους οποίους η σύνταξη δεν καθορίζει κανένα περιορισμό σχετικά με το αν θα πρέπει να είναι μέλη ή μη μέλη.
Εφόσον αλλάζουν το αριστερό τους όρισμα (μεταβάλλουν την κατάσταση της ροής), θα πρέπει, σύμφωνα με τους κανόνες του αντίχειρα, να υλοποιούνται ως μέλη του τύπου του αριστερού τους τελεστή. Ωστόσο, οι αριστεροί τελεστές τους είναι ροές από την πρότυπη βιβλιοθήκη, και ενώ οι περισσότεροι τελεστές εξόδου και εισόδου ροής που ορίζονται από την πρότυπη βιβλιοθήκη ορίζονται πράγματι ως μέλη των κλάσεων ροής, όταν υλοποιείτε πράξεις εξόδου και εισόδου για τους δικούς σας τύπους, δεν μπορείτε να αλλάξετε τους τύπους ροής της πρότυπης βιβλιοθήκης. Γι' αυτό πρέπει να υλοποιήσετε αυτούς τους τελεστές για τους δικούς σας τύπους ως συναρτήσεις που δεν είναι μέλη.
Οι κανονικές μορφές των δύο είναι οι εξής:
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// write obj to stream
return os;
}
std::istream& operator>>(std::istream& is, T& obj)
{
// read obj from stream
if( /* no valid object of T found in stream */ )
is.setstate(std::ios::failbit);
return is;
}
Κατά την υλοποίηση του operator>>
, η χειροκίνητη ρύθμιση της κατάστασης της ροής είναι απαραίτητη μόνο όταν η ίδια η ανάγνωση πέτυχε, αλλά το αποτέλεσμα δεν είναι αυτό που θα αναμενόταν.
Ο τελεστής κλήσης συνάρτησης, που χρησιμοποιείται για τη δημιουργία αντικειμένων συναρτήσεων, γνωστών και ως functors, πρέπει να ορίζεται ως συνάρτηση μέλους, οπότε έχει πάντα το έμμεσο όρισμα this
των συναρτήσεων μελών. Εκτός από αυτό, μπορεί να υπερφορτωθεί για να δέχεται οποιοδήποτε αριθμό πρόσθετων ορίων, συμπεριλαμβανομένου του μηδενός.
Ακολουθεί ένα παράδειγμα της σύνταξης:
class foo {
public:
// Overloaded call operator
int operator()(const std::string& y) {
// ...
}
};
Χρήση:
foo f;
int a = f("hello");
Σε όλη την τυπική βιβλιοθήκη της C++, τα αντικείμενα συναρτήσεων αντιγράφονται πάντα. Επομένως, τα δικά σας αντικείμενα συναρτήσεων θα πρέπει να είναι φτηνά για αντιγραφή. Αν ένα αντικείμενο συνάρτησης πρέπει οπωσδήποτε να χρησιμοποιήσει δεδομένα που είναι ακριβό να αντιγραφούν, είναι προτιμότερο να αποθηκεύσετε τα δεδομένα αυτά αλλού και το αντικείμενο συνάρτησης να αναφέρεται σε αυτά.
Οι δυαδικοί τελεστές σύγκρισης infix θα πρέπει, σύμφωνα με τους κανόνες του αντίχειρα, να υλοποιούνται ως συναρτήσεις μη-μέλους1. Η μοναδιαία άρνηση προθέματος !
θα πρέπει (σύμφωνα με τους ίδιους κανόνες) να υλοποιηθεί ως συνάρτηση-μέλος. (αλλά συνήθως δεν είναι καλή ιδέα να την υπερφορτώνετε).
Οι αλγόριθμοι (π.χ. std::sort()
) και οι τύποι (π.χ. std::map
) της πρότυπης βιβλιοθήκης θα περιμένουν πάντα μόνο την παρουσία του operator<
. Ωστόσο, οι _χρήστες του τύπου σας θα περιμένουν να είναι παρόντες και όλοι οι άλλοι τελεστές, οπότε αν ορίσετε τον operator<
, φροντίστε να ακολουθήσετε τον τρίτο θεμελιώδη κανόνα της υπερφόρτωσης τελεστών και να ορίσετε επίσης όλους τους άλλους τελεστές σύγκρισης boolean. Ο κανονικός τρόπος υλοποίησής τους είναι ο εξής:
inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}
inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator> (const X& lhs, const X& rhs){return operator< (rhs,lhs);}
inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}
inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}
Το σημαντικό πράγμα που πρέπει να σημειωθεί εδώ είναι ότι μόνο δύο από αυτούς τους τελεστές κάνουν πραγματικά κάτι, οι άλλοι απλά προωθούν τα ορίσματά τους σε έναν από αυτούς τους δύο για να κάνουν την πραγματική δουλειά.
Η σύνταξη για την υπερφόρτωση των υπόλοιπων δυαδικών τελεστών boolean (||
, &&
) ακολουθεί τους κανόνες των τελεστών σύγκρισης. Ωστόσο, είναι πολύ απίθανο να βρείτε μια λογική περίπτωση χρήσης για αυτούς2.
1 Όπως συμβαίνει με όλους τους κανόνες, μερικές φορές μπορεί να υπάρχουν λόγοι να παραβιάσετε και αυτόν. Αν είναι έτσι, μην ξεχνάτε ότι ο αριστερός τελεστής των δυαδικών τελεστών σύγκρισης, ο οποίος για τις συναρτήσεις-μέλη θα είναι *this
, πρέπει να είναι επίσης const
. Έτσι, ένας τελεστής σύγκρισης που υλοποιείται ως συνάρτηση-μέλος θα πρέπει να έχει την εξής υπογραφή:</sub>,
bool operator<(const X& rhs) const { /* do actual comparison with *this */ }
(Προσέξτε το const
στο τέλος.)</sub>,
2 Θα πρέπει να σημειωθεί ότι η ενσωματωμένη έκδοση των ||
και &&
χρησιμοποιούν σημασιολογία συντόμευσης. Ενώ οι οριζόμενες από τον χρήστη (επειδή είναι συντακτική ζάχαρη για κλήσεις μεθόδων) δεν χρησιμοποιούν σημασιολογία συντόμευσης. Ο χρήστης θα περιμένει από αυτούς τους τελεστές να έχουν σημασιολογία συντόμευσης και ο κώδικάς του μπορεί να εξαρτάται από αυτό, επομένως συνιστάται ιδιαίτερα να μην τους ορίσετε ΠΟΤΕ,
Οι μοναδιαίοι τελεστές προσαύξησης και μείωσης υπάρχουν τόσο σε προθεματική όσο και σε μεταθεματική μορφή. Για να ξεχωρίζει ο ένας από τον άλλο, οι παραλλαγές postfix λαμβάνουν ένα επιπλέον ψευδο-όρισμα int. Αν υπερφορτώσετε τους τελεστές increment ή decrement, φροντίστε να υλοποιείτε πάντα και τις δύο εκδόσεις prefix και postfix. Εδώ είναι η κανονική υλοποίηση του increment, το decrement ακολουθεί τους ίδιους κανόνες:
class X {
X& operator++()
{
// do actual increment
return *this;
}
X operator++(int)
{
X tmp(*this);
operator++();
return tmp;
}
};
Σημειώστε ότι η postfix παραλλαγή υλοποιείται με όρους του προθέματος. Σημειώστε επίσης ότι το postfix κάνει ένα επιπλέον αντίγραφο.2</sup>,
Η υπερφόρτωση των μοναδιαίων μείον και συν δεν είναι πολύ συνηθισμένη και μάλλον είναι καλύτερα να αποφεύγεται. Αν χρειαστεί, θα πρέπει πιθανώς να υπερφορτωθούν ως συναρτήσεις-μέλη.
2 Σημειώστε επίσης ότι η παραλλαγή postfix κάνει περισσότερη δουλειά και επομένως είναι λιγότερο αποδοτική στη χρήση από την παραλλαγή prefix. Αυτός είναι ένας καλός λόγος για να προτιμάτε γενικά την αύξηση προθέματος έναντι της αύξησης μεταθέματος. Ενώ οι μεταγλωττιστές μπορούν συνήθως να βελτιστοποιήσουν την πρόσθετη εργασία της postfix increment για ενσωματωμένους τύπους, μπορεί να μην είναι σε θέση να κάνουν το ίδιο για τύπους που ορίζονται από τον χρήστη (που μπορεί να είναι κάτι τόσο αθώο όσο ένας επαναλήπτης λίστας). Μόλις συνηθίσετε να κάνετε i++
, γίνεται πολύ δύσκολο να θυμάστε να κάνετε ++i
αντί για i
όταν το i
δεν είναι ενσωματωμένος τύπος (επιπλέον θα πρέπει να αλλάξετε κώδικα όταν αλλάζετε έναν τύπο), οπότε είναι καλύτερα να συνηθίσετε να χρησιμοποιείτε πάντα prefix increment, εκτός αν απαιτείται ρητά postfix.</sub>,
Για τους δυαδικούς αριθμητικούς τελεστές, μην ξεχνάτε να υπακούετε στον τρίτο βασικό κανόνα υπερφόρτωσης τελεστών: Αν παρέχετε το +
, παρέχετε επίσης το +=
, αν παρέχετε το -
, μην παραλείπετε το -=
, κ.λπ. Ο Andrew Koenig λέγεται ότι ήταν ο πρώτος που παρατήρησε ότι οι σύνθετοι τελεστές ανάθεσης μπορούν να χρησιμοποιηθούν ως βάση για τους μη σύνθετους αντίστοιχους. Δηλαδή, ο τελεστής +
υλοποιείται με όρους του +=
, ο -
υλοποιείται με όρους του -=
κ.λπ.
Σύμφωνα με τους κανόνες μας, ο +
και οι συνοδοί του θα πρέπει να είναι μη μέλη, ενώ οι αντίστοιχοι σύνθετοι τελεστές ανάθεσης (+=
κ.λπ.), αλλάζοντας το αριστερό τους όρισμα, θα πρέπει να είναι μέλη. Εδώ είναι ο υποδειγματικός κώδικας για τους +=
και +
- οι άλλοι δυαδικοί αριθμητικοί τελεστές θα πρέπει να υλοποιηθούν με τον ίδιο τρόπο:
class X {
X& operator+=(const X& rhs)
{
// actual addition of rhs to *this
return *this;
}
};
inline X operator+(X lhs, const X& rhs)
{
lhs += rhs;
return lhs;
}
Ο τελεστής +=
επιστρέφει το αποτέλεσμά του ανά αναφορά, ενώ ο τελεστής +
επιστρέφει ένα αντίγραφο του αποτελέσματός του. Φυσικά, η επιστροφή μιας αναφοράς είναι συνήθως πιο αποδοτική από την επιστροφή ενός αντιγράφου, αλλά στην περίπτωση του operator+
, δεν υπάρχει τρόπος να παρακάμψουμε την αντιγραφή. Όταν γράφετε a + b
, περιμένετε το αποτέλεσμα να είναι μια νέα τιμή, γι' αυτό και ο operator+
πρέπει να επιστρέψει μια νέα τιμή.3</sup>,
Σημειώστε επίσης ότι ο operator+
παίρνει τον αριστερό του τελεστή με αντιγραφή και όχι με αναφορά const. Ο λόγος γι' αυτό είναι ο ίδιος με τον λόγο που δίνεται για τον operator=
που παίρνει το όρισμά του ανά αντίγραφο.
Οι τελεστές χειρισμού bit ~
&
|
^
<<
>>
θα πρέπει να υλοποιηθούν με τον ίδιο τρόπο όπως οι αριθμητικοί τελεστές. Ωστόσο, (εκτός από την υπερφόρτωση των τελεστών <<
και >>
για έξοδο και είσοδο) υπάρχουν πολύ λίγες λογικές περιπτώσεις χρήσης για την υπερφόρτωσή τους.
3 Και πάλι, το μάθημα που πρέπει να πάρουμε από αυτό είναι ότι το a += b
είναι, γενικά, πιο αποδοτικό από το a + b
και θα πρέπει να προτιμάται αν είναι δυνατόν.</sub>,
Ο τελεστής υπογραφής πίνακα είναι ένας δυαδικός τελεστής που πρέπει να υλοποιηθεί ως μέλος της κλάσης. Χρησιμοποιείται για τύπους που μοιάζουν με δοχεία και επιτρέπουν την πρόσβαση στα στοιχεία δεδομένων τους μέσω ενός κλειδιού. Η κανονική μορφή παροχής αυτών είναι η εξής:
class X {
value_type& operator[](index_type idx);
const value_type& operator[](index_type idx) const;
// ...
};
Εκτός αν δεν θέλετε οι χρήστες της κλάσης σας να είναι σε θέση να αλλάξουν τα στοιχεία δεδομένων που επιστρέφονται από τον operator[]
(οπότε μπορείτε να παραλείψετε τη μη-const παραλλαγή), θα πρέπει πάντα να παρέχετε και τις δύο παραλλαγές του τελεστή.
Αν είναι γνωστό ότι ο value_type αναφέρεται σε έναν ενσωματωμένο τύπο, η const παραλλαγή του τελεστή θα πρέπει καλύτερα να επιστρέφει ένα αντίγραφο αντί για μια const αναφορά:
class X {
value_type& operator[](index_type idx);
value_type operator[](index_type idx) const;
// ...
};
Για να ορίσετε τους δικούς σας επαναλήπτες ή έξυπνους δείκτες, πρέπει να υπερφορτώσετε τον μοναδιαίο τελεστή απομάκρυνσης προθέματος *
και τον δυαδικό τελεστή πρόσβασης μέλους δείκτη infix ->
:
class my_ptr {
value_type& operator*();
const value_type& operator*() const;
value_type* operator->();
const value_type* operator->() const;
};
->
, αν ο value_type
είναι τύπου class
(ή struct
ή union
), ένας άλλος operator->()
καλείται αναδρομικά, μέχρις ότου ένας operator->()
επιστρέψει μια τιμή μη τύπου class.
Ο μοναδιαίος τελεστής address-of δεν πρέπει ποτέ να υπερφορτώνεται.
Για operator->*()
βλέπε αυτή την ερώτηση. Χρησιμοποιείται σπάνια και συνεπώς σπάνια υπερφορτώνεται. Στην πραγματικότητα, ακόμη και οι επαναλήπτες δεν τον υπερφορτώνουν.Συνέχεια στην Τελεστές μετατροπής
Όταν πρόκειται για την υπερφόρτωση τελεστών στη C++, υπάρχουν τρεις βασικοί κανόνες που πρέπει να ακολουθήσετε. Όπως συμβαίνει με όλους αυτούς τους κανόνες, υπάρχουν πράγματι εξαιρέσεις. Μερικές φορές οι άνθρωποι έχουν παρεκκλίνει από αυτούς και το αποτέλεσμα δεν ήταν κακός κώδικας, αλλά τέτοιες θετικές αποκλίσεις είναι λίγες και σπάνιες. Τουλάχιστον, οι 99 από τις 100 τέτοιες αποκλίσεις που έχω δει ήταν αδικαιολόγητες. Ωστόσο, θα μπορούσαν κάλλιστα να είναι 999 στις 1000. Γι' αυτό καλύτερα να τηρήσετε τους παρακάτω κανόνες.
Όποτε η σημασία ενός τελεστή δεν είναι προφανώς σαφής και αδιαμφισβήτητη, δεν πρέπει να υπερφορτώνεται. Αντ' αυτού, παρέχετε μια συνάρτηση με ένα καλά επιλεγμένο όνομα. Βασικά, ο πρώτος και κυριότερος κανόνας για την υπερφόρτωση τελεστών, στην καρδιά του, λέει: Μην το κάνετε. Αυτό μπορεί να φαίνεται παράξενο, επειδή υπάρχουν πολλά που πρέπει να γνωρίζουμε για την υπερφόρτωση τελεστών και έτσι πολλά άρθρα, κεφάλαια βιβλίων και άλλα κείμενα ασχολούνται με όλα αυτά. Όμως, παρά αυτές τις φαινομενικά προφανείς ενδείξεις, υπάρχουν μόνο εκπληκτικά λίγες περιπτώσεις όπου η υπερφόρτωση τελεστών είναι κατάλληλη. Ο λόγος είναι ότι στην πραγματικότητα είναι δύσκολο να κατανοήσουμε τη σημασιολογία πίσω από την εφαρμογή ενός τελεστή, εκτός αν η χρήση του τελεστή στο πεδίο εφαρμογής είναι γνωστή και αδιαμφισβήτητη. Σε αντίθεση με τη δημοφιλή πεποίθηση, αυτό δεν συμβαίνει σχεδόν ποτέ.
Μείνετε πάντα στη γνωστή σημασιολογία του τελεστή.
Η C++ δεν θέτει περιορισμούς στη σημασιολογία των υπερφορτωμένων τελεστών. Ο μεταγλωττιστής σας θα δεχτεί ευχαρίστως κώδικα που υλοποιεί τον δυαδικό τελεστή +
για να αφαιρεί από τον δεξιό τελεστή του. Ωστόσο, οι χρήστες ενός τέτοιου τελεστή δεν θα υποψιάζονταν ποτέ την έκφραση a + b
για να αφαιρέσουν το a
από το b
. Φυσικά, αυτό προϋποθέτει ότι η σημασιολογία του τελεστή στο πεδίο εφαρμογής είναι αδιαμφισβήτητη.
Πάντα να παρέχετε όλα από ένα σύνολο σχετικών πράξεων.
Οι τελεστές σχετίζονται μεταξύ τους και με άλλες πράξεις. Αν ο τύπος σας υποστηρίζει την πράξη a + b
, οι χρήστες θα περιμένουν να μπορούν να καλέσουν και την πράξη a += b
. Αν υποστηρίζει την προσαύξηση με πρόθεμα ++a
, θα περιμένουν να λειτουργήσει και η a++
. Αν μπορούν να ελέγξουν αν a < b
, σίγουρα θα περιμένουν να μπορούν να ελέγξουν επίσης αν a > b
. Αν μπορούν να αντιγράψουν-κατασκευάσουν τον τύπο σας, περιμένουν να λειτουργήσει και η ανάθεση.
Συνεχίστε στην Η απόφαση μεταξύ μέλους και μη μέλους.
Δεν μπορείτε να αλλάξετε τη σημασία των τελεστών για ενσωματωμένους τύπους στη C++, οι τελεστές μπορούν να υπερφορτωθούν μόνο για τύπους που ορίζονται από το χρήστη1. Δηλαδή, τουλάχιστον ένας από τους τελεστές πρέπει να είναι ενός τύπου που έχει οριστεί από το χρήστη. Όπως και με άλλες υπερφορτωμένες συναρτήσεις, οι τελεστές μπορούν να υπερφορτωθούν για ένα συγκεκριμένο σύνολο παραμέτρων μόνο μία φορά.
Δεν μπορούν να υπερφορτωθούν όλοι οι τελεστές στη C++. Μεταξύ των τελεστών που δεν μπορούν να υπερφορτωθούν είναι: .*
και ο μόνος τριμερής τελεστής στη C++, ?:
Μεταξύ των τελεστών που μπορούν να υπερφορτωθούν στη C++ είναι οι εξής:
+
-
*
/
%
και +=
-=
*=
/=
%=
(όλα τα δυαδικά infix), +
-
(μοναδιαίο πρόθεμα), ++
--
(μοναδιαίο πρόθεμα και μετάθεμα).&
|
^
<<
>>
και &=
|=
^=
<<=
>>=
(όλα τα δυαδικά επιθήματα)- ~
(μοναδιαίο πρόθεμα).==
!=
<
>
<=
>=
||
&&
(όλα τα δυαδικά επιθήματα); !
(μοναδιαίο πρόθεμα)new
new[]
delete
delete[]
=
[]
->
->*
,
(όλα τα δυαδικά επιθέματα)- *
&
(όλα τα μοναδιαία προθέματα)- ()
(κλήση συνάρτησης, n-αρχικό πρόθεμα)Ωστόσο, το γεγονός ότι μπορείτε να υπερφορτώσετε όλα αυτά δεν σημαίνει ότι πρέπει να το κάνετε. Δείτε τους βασικούς κανόνες υπερφόρτωσης τελεστών.
Στη C++, οι τελεστές υπερφορτώνονται με τη μορφή συναρτήσεων με ειδικά ονόματα. Όπως και με άλλες συναρτήσεις, οι υπερφορτωμένοι τελεστές μπορούν γενικά να υλοποιηθούν είτε ως συνάρτηση-μέλος του αριστερού τελεστή τους's τύπου είτε ως συναρτήσεις-μη μέλη. Το αν είστε ελεύθεροι να επιλέξετε ή υποχρεωμένοι να χρησιμοποιήσετε οποιαδήποτε από τις δύο εξαρτάται από διάφορα κριτήρια.2</sup>- Ένας μοναδιαίος τελεστής @
3</sup>-, που εφαρμόζεται σε ένα αντικείμενο x, καλείται είτε ως operator@(x)
είτε ως x.operator@()
. Ένας δυαδικός infix τελεστής @
, που εφαρμόζεται στα αντικείμενα x
και y
, καλείται είτε ως operator@(x,y)
είτε ως x.operator@(y)
.4</sup>,
Οι τελεστές που υλοποιούνται ως συναρτήσεις μη-μέλους είναι μερικές φορές φίλοι του τύπου του τελεστή τους.
1Ο όρος "ορισμένος από το χρήστη" μπορεί να είναι ελαφρώς παραπλανητικός. Η C++ κάνει τη διάκριση μεταξύ ενσωματωμένων τύπων και τύπων που ορίζονται από τον χρήστη. Στους πρώτους ανήκουν, για παράδειγμα, οι τύποι int, char και double- στους δεύτερους ανήκουν όλοι οι τύποι struct, class, union και enum, συμπεριλαμβανομένων και εκείνων της τυπικής βιβλιοθήκης, παρόλο που δεν ορίζονται, ως τέτοιοι, από τους χρήστες.</sub>,
2 Αυτό καλύπτεται σε ένα μεταγενέστερο μέρος των παρόντων FAQ.</sub>,
3 Το @
δεν είναι έγκυρος τελεστής στη C++ και γι' αυτό το λόγο το χρησιμοποιώ ως placeholder.</sub>,
4 Ο μόνος τριμερής τελεστής στη C++ δεν μπορεί να υπερφορτωθεί και ο μόνος n-μερής τελεστής πρέπει πάντα να υλοποιείται ως συνάρτηση-μέλος.</sub>,
Συνεχίστε στην ενότητα Οι τρεις βασικοί κανόνες υπερφόρτωσης τελεστών στη C++.