cpp:casting
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| cpp:casting [2026/04/24 11:56] – [Παράδειγμα 2ο: Κληρονομικότητα (Upcasting & Downcasting)] gthanos | cpp:casting [2026/04/24 12:28] (current) – [reinterpret_cast<>] gthanos | ||
|---|---|---|---|
| Line 99: | Line 99: | ||
| <WRAP tip> | <WRAP tip> | ||
| - | Χρησιμοποιήστε **static_cast** μόνο όταν η μετατροπή τύπου είναι απόλυτα λογική | + | Χρησιμοποιήστε **static_cast** μόνο όταν |
| + | * η μετατροπή τύπου είναι απόλυτα λογική, για | ||
| + | < | ||
| + | * είναι σίγουρο ότι το casting δεν θα αποτύχει σε καμία περίπτωση. Για παράδειγμα, | ||
| + | < | ||
| + | Derived derived(100); | ||
| + | Base& b = static_cast< | ||
| + | </ | ||
| + | |||
| + | Το **static_cast** εφαρμόζεται σχεδόν στα πάντα: | ||
| + | |||
| + | * **Κανονικούς Τύπους: | ||
| + | * **Pointers: | ||
| + | * **References**: | ||
| + | * **Enums:** Μετατροπή enums σε integers και αντίστροφα. | ||
| + | |||
| + | **Σημαντικό: | ||
| </ | </ | ||
| - | ====== dynamic_cast<> | + | ===== dynamic_cast<> |
| + | Το **dynamic_cast** είναι ο τύπος casting που εφαρμόζεται στον πολυμορφισμό. Το χρησιμοποιούμε όταν έχουμε έναν δείκτη προς μια βασική κλάση (Base*) και εξετάζουμε αν το αντικείμενο στο οποίο δείχνει είναι μια συγκεκριμένη παράγωγη κλάση (Derived*). | ||
| + | Ακολουθεί ένα σενάριο από ένα σύστημα πληρωμών, | ||
| - | ====== const_cast<> | + | <code cpp account_polymorphism.cpp> |
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // Η Base κλάση πρέπει να είναι πολυμορφική (να έχει τουλάχιστον μία virtual function) | ||
| + | class Account { | ||
| + | public: | ||
| + | virtual void withdraw(double amount) { | ||
| + | std::cout << " | ||
| + | } | ||
| + | virtual ~Account() {} // Απαραίτητος ΠΑΝΤΑ ο virtual destructor | ||
| + | }; | ||
| + | |||
| + | class SavingsAccount : public Account { | ||
| + | public: | ||
| + | void applyInterest() { | ||
| + | std::cout << " | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | class CheckingAccount : public Account { | ||
| + | public: | ||
| + | void printStatement() { | ||
| + | std::cout << " | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | void processAccount(Account* acc) { | ||
| + | // Θέλουμε να καλέσουμε την applyInterest(), | ||
| + | // Χρησιμοποιούμε dynamic_cast για να ελέγξουμε με ασφάλεια. | ||
| + | |||
| + | SavingsAccount* savings | ||
| + | |||
| + | if (savings != nullptr) { | ||
| + | // Η μετατροπή πέτυχε! Το acc δείχνει όντως σε SavingsAccount. | ||
| + | savings-> | ||
| + | } else { | ||
| + | // Η μετατροπή απέτυχε. Το acc είναι κάτι άλλο (π.χ. CheckingAccount). | ||
| + | std::cout << " | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int main() { | ||
| + | // Δημιουργούμε ένα vector από διαφορετικούς λογαριασμούς (Base pointers) | ||
| + | std:: | ||
| + | bank_vault.push_back(new SavingsAccount()); | ||
| + | bank_vault.push_back(new CheckingAccount()); | ||
| + | |||
| + | for (Account* acc : bank_vault) { | ||
| + | processAccount(acc); | ||
| + | delete acc; | ||
| + | } | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <WRAP tip 80% center round> | ||
| + | |||
| + | * **Runtime Check: | ||
| + | * **Ασφάλεια (Safety):** Αν χρησιμοποιούσαμε **static_cast** και το αντικείμενο ήταν τύπου CheckingAccount, | ||
| + | * **Πολυμορφισμός: | ||
| + | * **Δε λειτουργεί για κανονικούς τύπους: | ||
| + | |||
| + | </ | ||
| + | |||
| + | **Συνοπτικός Πίνακας** | ||
| + | |||
| + | ^ Τύπος | ||
| + | ^ Βασικοί Τύποι (int, double, κλπ) | ||
| + | ^ Pointers (Base* -> Derived*) | ||
| + | ^ References (Base& -> Derived& | ||
| + | ^ Enums | Ναι | ||
| + | |||
| + | |||
| + | ===== const_cast<> | ||
| + | |||
| + | Είναι ο μόνος τελεστής που μπορεί να προσθέσει ή να αφαιρέσει το const (ή το volatile) από μια μεταβλητή. | ||
| + | |||
| + | * **Γιατί να το κάνεις: | ||
| + | * **Ο Κίνδυνος: | ||
| + | |||
| + | <code cpp cost_cast.cpp> | ||
| + | void legacy_function(char* str) { | ||
| + | /* ... */ | ||
| + | } | ||
| + | |||
| + | const char* my_text | ||
| + | // legacy_function(my_text); | ||
| + | legacy_function(const_cast< | ||
| + | </ | ||
| ====== reinterpret_cast<> | ====== reinterpret_cast<> | ||
| + | |||
| + | Αυτός είναι ο πιο ισχυρός και επικίνδυνος τελεστής. Λέει στον compiler: " | ||
| + | |||
| + | **Τι κάνει: | ||
| + | |||
| + | **Προσοχή: | ||
| + | |||
| + | <code cpp reinterpret_cast.cpp> | ||
| + | long address = 0x7FFF1234; | ||
| + | // Ερμήνευσε αυτόν τον αριθμό ως διεύθυνση μνήμης ενός ακεραίου | ||
| + | int* p = reinterpret_cast< | ||
| + | </ | ||
| + | |||
| + | Ο συγκεκριμένος τελεστής μοιάζει με το type casting που γνωρίζουμε από τη γλώσσα C, διότι ο μεταγλωττιστής ακολουθεί χωρίς έλεγχο τις οδηγίες του προγραμματιστή. | ||
| + | |||
| + | |||
cpp/casting.1777031783.txt.gz · Last modified: 2026/04/24 11:56 by gthanos
