User Tools

Site Tools


cpp:class_templates_specialization

This is an old revision of the document!


Εξειδίκευση ενός υφιστάμενου template

Συχνά είναι απαραίτητο να προδιαγράψουμε διαφορετική λειτουργικότητα σε ένα template με βάση τον τύπο των δεδομένων που θα εισαχθεί τελικά στην κλάση. Για παράδειγμα, για την κλάση Box<T> που είδαμε προηγουμένως, οφείλουμε να εισάγουμε διαφορετική λειτουργικότητα όταν ο τύπος δεδομένων είναι δείκτης αντί για κανονική μεταβλητή. Ο λόγος είναι ότι σε αυτή την περίπτωση δεν αρκεί η απλή αντιγραφεί του δείκτη, αλλά θα πρέπει να δεσμευθεί ο απαραίτητος χώρος στη μνήμη προκειμένου η κλάση να δημιουργήσει ένα αντίγραφο της υφιστάμενης πληροφορίας που περνιέται μέσω του δείκτη. Το παράδειγμα εξειδίκευσης της κλάσης Box<T> όταν περνιέται δείκτης δίνεται παρακάτω:

BoxPtr.hpp
#ifndef _BOXTPTR_HPP_
#define _BOXTPTR_HPP_
#include "Box.hpp"
template<typename T>
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>
Box<T*>::Box() {
  this->e = nullptr;
}
 
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() {
  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

Παρακάτω παρατίθεται κώδικας ο οποίος χρησιμοποιεί την παραπάνω εξειδίκευση του template.

BoxPtrUsage.hpp
#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;
}

<TODO tip 80% center round> Στον παραπάνω κώδικα αντικαταστήστε την εντολή #include “BoxPtr.hpp” με την εντολή #include “Box.hpp” και παρατηρήστε την αλλαγή στη συμπεριφορά του προγράμματος </TODO>

Το παραπάνω παράδειγμα είναι ικανοποιητικό εάν περαστεί ως δείκτης ένα αντικείμενο τύπου int* ή Student* , όμως δεν είναι ικανοποιητικό εάν περαστεί ένας δείκτης τύπου char* που αντιπροσωπεύει ένα C string. Σε αυτή την περίπτωση δεν αρκεί να δεσμευθεί η μνήμη για ένα χαρακτήρα, αλλά θα πρέπει α) να αναγνωρίσουμε το μέγεθος της συμβολοσειράς που πρέπει να αντιγραφεί και β)πριν γίνει η αντιγραφή της συμβολοσειράς να δεσμευθεί ο απαραίτητος χώρος για αυτή.

BoxCharPtr.hpp
#ifndef _BOXCHARPTR_HPP_
#define _BOXCHARPTR_HPP_
template <>
class Box<char *> {
  char *e;
public:
  Box();
  Box(char *e);
  ~Box();
  Box(const Box<char*>& b);
  char* get() const;
  void set(char *e);
  Box<char*>& operator=(Box<char*>& b);
  friend std::ostream& operator<<(std::ostream& out, const Box<char*>& t);
};
 
Box<char*>::Box() {
  this->e = nullptr;
}
 
Box<char*>::Box(char *e) {
  this->e = new char[strlen(e)+1];
  strcpy(this->e, e);
}
 
Box<char*>::Box(const Box<char*>& b) {
  this->e = new char[strlen(b.e)+1];
  strcpy(this->e, b.e);
}
 
Box<char*>::~Box() {
  delete [] this->e;
}
 
char* Box<char*>::get() const { 
  char *ce = new char[strlen(e)+1];
  strcpy(ce, e);
  return ce;
}
 
void Box<char *>::set(char *e) {
  if(this->e!=nullptr)
    delete [] this->e;
  this->e = new char[strlen(e)+1];
  strcpy(this->e, e);
}
 
Box<char*>& Box<char*>::operator=(Box<char*>& b){
  set(b.e);
  return *this;
}
 
std::ostream& operator<<(std::ostream& out, const Box<char*>& t) {
  out << t.e;
  return out;
}
#endif
cpp/class_templates_specialization.1557832540.txt.gz · Last modified: 2019/05/14 10:15 (external edit)