User Tools

Site Tools


cpp:class_templates_specialization

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
cpp:class_templates_specialization [2019/05/14 04:23] gthanoscpp:class_templates_specialization [2022/05/26 10:47] (current) – [Εξειδίκευση της κλάσης Box στην περίπτωση που η παράμετρος είναι δείκτης σε χαρακτήρα] gthanos
Line 1: Line 1:
 ====== Εξειδίκευση ενός υφιστάμενου template ====== ====== Εξειδίκευση ενός υφιστάμενου template ======
 +
 +===== Εξειδίκευση της κλάσης Box στην περίπτωση που η παράμετρος είναι δείκτης =====
  
 Συχνά είναι απαραίτητο να προδιαγράψουμε διαφορετική λειτουργικότητα σε ένα template με βάση τον τύπο των δεδομένων που θα εισαχθεί τελικά στην κλάση. Για παράδειγμα, για την κλάση **Box<T>** που είδαμε προηγουμένως, οφείλουμε να εισάγουμε διαφορετική λειτουργικότητα όταν ο τύπος δεδομένων είναι δείκτης αντί για κανονική μεταβλητή. Ο λόγος είναι ότι σε αυτή την περίπτωση δεν αρκεί η απλή αντιγραφεί του δείκτη, αλλά θα πρέπει να δεσμευθεί ο απαραίτητος χώρος στη μνήμη προκειμένου η κλάση να δημιουργήσει ένα αντίγραφο της υφιστάμενης πληροφορίας που περνιέται μέσω του δείκτη. Το παράδειγμα εξειδίκευσης της κλάσης **Box<T>** όταν περνιέται δείκτης δίνεται παρακάτω: Συχνά είναι απαραίτητο να προδιαγράψουμε διαφορετική λειτουργικότητα σε ένα template με βάση τον τύπο των δεδομένων που θα εισαχθεί τελικά στην κλάση. Για παράδειγμα, για την κλάση **Box<T>** που είδαμε προηγουμένως, οφείλουμε να εισάγουμε διαφορετική λειτουργικότητα όταν ο τύπος δεδομένων είναι δείκτης αντί για κανονική μεταβλητή. Ο λόγος είναι ότι σε αυτή την περίπτωση δεν αρκεί η απλή αντιγραφεί του δείκτη, αλλά θα πρέπει να δεσμευθεί ο απαραίτητος χώρος στη μνήμη προκειμένου η κλάση να δημιουργήσει ένα αντίγραφο της υφιστάμενης πληροφορίας που περνιέται μέσω του δείκτη. Το παράδειγμα εξειδίκευσης της κλάσης **Box<T>** όταν περνιέται δείκτης δίνεται παρακάτω:
  
-<code cpp BoxTPtr.hpp>+<code cpp BoxPtr.hpp>
 #ifndef _BOXTPTR_HPP_ #ifndef _BOXTPTR_HPP_
 #define _BOXTPTR_HPP_ #define _BOXTPTR_HPP_
 +
 #include "Box.hpp" #include "Box.hpp"
 +
 template<typename T> template<typename T>
 class Box<T*> { class Box<T*> {
Line 74: Line 78:
 #endif #endif
 </code> </code>
 +
 +Παρακάτω παρατίθεται κώδικας ο οποίος χρησιμοποιεί την παραπάνω εξειδίκευση του //template//
 +
 +<code cpp BoxPtrUsage.cpp>
 +#include <iostream>
 +#include "BoxPtr.hpp"
 +#include "Student.hpp"
 +
 +using namespace std;
 +
 +int main() {
 +  int a=5;
 +  double d(4.23);
 +  Student kate = {"Kate", 1234};
 +  
 +  Box<int*> intBox(&a);
 +  Box<double*> doubleBox(&d);
 +  Box<Student*> studentBox(&kate);
 +  Student* kate_ptr = studentBox.get();
 +    
 +  cout << *kate_ptr << endl;
 +  delete kate_ptr;
 +  kate.setName("Katerina");
 +  cout << kate << endl;
 +}
 +</code>
 +
 +<WRAP todo 80% center round>
 +Στον παραπάνω κώδικα αντικαταστήστε την  εντολή ''#include "BoxPtr.hpp"'' με την εντολή ''#include "Box.hpp"'' και παρατηρήστε την αλλαγή στη συμπεριφορά του προγράμματος. To πρόγραμμα θα τερματίσει τη λειτουργία του (Γιατί?) με ένα μήνυμα της μορφής:
 +<code>
 +*** Error in `./BoxPtrUsage': double free or corruption (out): 0x00007ffc4f49ed10 ***
 +======= Backtrace: =========
 +/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f40da1757e5]
 +/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f40da17e37a]
 +/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f40da18253c]
 +</code>
 +</WRAP>
 +
 +===== Εξειδίκευση της κλάσης Box στην περίπτωση που η παράμετρος είναι δείκτης σε χαρακτήρα =====
  
 Το παραπάνω παράδειγμα είναι ικανοποιητικό εάν περαστεί ως δείκτης ένα αντικείμενο τύπου **int* ** ή **Student* **, όμως δεν είναι ικανοποιητικό εάν περαστεί ένας δείκτης τύπου **char* ** που αντιπροσωπεύει ένα C string. Σε αυτή την περίπτωση δεν αρκεί να δεσμευθεί η μνήμη για ένα χαρακτήρα, αλλά θα πρέπει α) να αναγνωρίσουμε το μέγεθος της συμβολοσειράς που πρέπει να αντιγραφεί και β)πριν γίνει η αντιγραφή της συμβολοσειράς να δεσμευθεί ο απαραίτητος χώρος για αυτή. Το παραπάνω παράδειγμα είναι ικανοποιητικό εάν περαστεί ως δείκτης ένα αντικείμενο τύπου **int* ** ή **Student* **, όμως δεν είναι ικανοποιητικό εάν περαστεί ένας δείκτης τύπου **char* ** που αντιπροσωπεύει ένα C string. Σε αυτή την περίπτωση δεν αρκεί να δεσμευθεί η μνήμη για ένα χαρακτήρα, αλλά θα πρέπει α) να αναγνωρίσουμε το μέγεθος της συμβολοσειράς που πρέπει να αντιγραφεί και β)πριν γίνει η αντιγραφή της συμβολοσειράς να δεσμευθεί ο απαραίτητος χώρος για αυτή.
Line 80: Line 123:
 #ifndef _BOXCHARPTR_HPP_ #ifndef _BOXCHARPTR_HPP_
 #define _BOXCHARPTR_HPP_ #define _BOXCHARPTR_HPP_
 +
 +#include "Box.hpp"
 +#include <cstring>
 +
 template <> template <>
 class Box<char *> { class Box<char *> {
Line 136: Line 183:
 #endif #endif
 </code> </code>
 +
 +Παράδειγμα κώδικα που χρησιμοποιεί την παραπάνω εξειδικευμένη κλάση **Box<char*>** δίνεται παρακάτω:
 +<code cpp BoxCharPtrUsage.cpp>
 +#include <iostream>
 +
 +#include "BoxCharPtr.hpp"
 +
 +using namespace std;
 +
 +int main() {
 +  char greeting[64] = "Wellcome C++ in CE325 course";
 +  
 +  Box<char*> greetingBox(greeting);
 +  
 +  char* greeting_copy = greetingBox.get();
 +  cout << greeting_copy << endl;
 +  delete greeting_copy;
 +  
 +  Box<char*> msgBox = greetingBox;
 +  char* msg = msgBox.get();
 +  cout << msg << endl;
 +  delete msg; 
 +}
 +</code>
 +
 +<WRAP todo 80% center round>
 +Στον παραπάνω κώδικα αντικαταστήστε την εντολή ''#include "BoxCharPtr.hpp"'' με την εντολή ''#include "BoxPtr.hpp"'' και στη συνέχεια με την εντολή ''#include "Box.hpp"''. Παρατηρήστε την αλλαγή στη συμπεριφορά του προγράμματος. Σε τι οφείλεται αυτό;
 +</WRAP>
cpp/class_templates_specialization.1557807838.txt.gz · Last modified: 2019/05/14 03:23 (external edit)