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 10:37] 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>** όταν περνιέται δείκτης δίνεται παρακάτω:
Line 6: Line 8:
 #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 77: Line 81:
 Παρακάτω παρατίθεται κώδικας ο οποίος χρησιμοποιεί την παραπάνω εξειδίκευση του //template// Παρακάτω παρατίθεται κώδικας ο οποίος χρησιμοποιεί την παραπάνω εξειδίκευση του //template//
  
-</code cpp BoxPtr.hpp+<code cpp BoxPtrUsage.cpp
-#ifndef _BOXTPTR_HPP_ +#include <iostream> 
-#define _BOXTPTR_HPP_ +#include "BoxPtr.hpp" 
-#include "Box.hpp"+#include "Student.hpp"
  
-template<typename T> +using namespace std;
-class Box<T*>+
-  T *e; +
-public: +
-  Box(); +
-  Box(T* e); +
-  Box(const Box<T*>& b); +
-  ~Box(); +
-  T* get() const; +
-  void set(T* e); +
-  template <T*> +
-  friend std::ostream& operator<<(std::ostream& out, const Box<T*>& t); +
-  Box<T*>& operator=(Box<T*>& b); +
-};+
  
-template <typename T+int main() { 
-Box<T*>::Box() { +  int a=5; 
-  this->nullptr;+  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;
 } }
- 
-template <typename T> 
-Box<T*>::Box(T* e) { 
-  this->e = new T; 
-  *(this->e) = *e; 
-} 
- 
-template <typename T> 
-Box<T*>::Box(const Box<T*>& b) { 
-  this->e = new T; 
-  *(this->e) = *b.e; 
-} 
- 
-template <typename T> 
-Box<T*>::~Box() { 
-  std::cerr << "Box destructor: " << *e << std::endl; 
-  delete this->e; 
-} 
- 
-template <typename T> 
-T* Box<T*>::get() const {  
-  T *ce = new T; 
-  *ce = *e; 
-  return ce; 
-} 
- 
-template <typename T> 
-void Box<T*>::set(T *e) {  
-  if(this->e != nullptr) 
-    delete this->e; 
-  this->e = new T; 
-  *(this->e) = *e; 
-} 
- 
-template <typename T> 
-std::ostream& operator<<(std::ostream& out, const Box<T*>& t) { 
-  T* ptr = t.get(); 
-  out << *ptr; 
-  delete ptr; 
-  return out; 
-} 
- 
-template <typename T> 
-Box<T*>& Box<T*>::operator=(Box<T*>& b){ 
-  set(b.e); 
-  return *this; 
-} 
-#endif 
 </code> </code>
  
-<TODO tip 80% center round> +<WRAP todo 80% center round> 
-Στον παραπάνω κώδικα αντικαταστήστε την  εντολή ''#include "BoxPtr.hpp"'' με την εντολή ''#include "BoxPtr.hpp"''+Στον παραπάνω κώδικα αντικαταστήστε την  εντολή ''#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> </code>
 +</WRAP>
 +
 +===== Εξειδίκευση της κλάσης Box στην περίπτωση που η παράμετρος είναι δείκτης σε χαρακτήρα =====
  
 Το παραπάνω παράδειγμα είναι ικανοποιητικό εάν περαστεί ως δείκτης ένα αντικείμενο τύπου **int* ** ή **Student* **, όμως δεν είναι ικανοποιητικό εάν περαστεί ένας δείκτης τύπου **char* ** που αντιπροσωπεύει ένα C string. Σε αυτή την περίπτωση δεν αρκεί να δεσμευθεί η μνήμη για ένα χαρακτήρα, αλλά θα πρέπει α) να αναγνωρίσουμε το μέγεθος της συμβολοσειράς που πρέπει να αντιγραφεί και β)πριν γίνει η αντιγραφή της συμβολοσειράς να δεσμευθεί ο απαραίτητος χώρος για αυτή. Το παραπάνω παράδειγμα είναι ικανοποιητικό εάν περαστεί ως δείκτης ένα αντικείμενο τύπου **int* ** ή **Student* **, όμως δεν είναι ικανοποιητικό εάν περαστεί ένας δείκτης τύπου **char* ** που αντιπροσωπεύει ένα C string. Σε αυτή την περίπτωση δεν αρκεί να δεσμευθεί η μνήμη για ένα χαρακτήρα, αλλά θα πρέπει α) να αναγνωρίσουμε το μέγεθος της συμβολοσειράς που πρέπει να αντιγραφεί και β)πριν γίνει η αντιγραφή της συμβολοσειράς να δεσμευθεί ο απαραίτητος χώρος για αυτή.
Line 160: 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 216: 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.1557830254.txt.gz · Last modified: 2019/05/14 09:37 (external edit)