C++学习之模板应用 ---array、smartptr、stack
有array(数组)、smartptr(智能指针)、stack(栈);
一、array:
1、我们实现了指针访问和下标访问。C++中指针访问常用迭代器来代替。
2、这里我们也揭示了 size_type、iterator、[] 、begin()、end()、size()的真实面目;
Array.hpp
1 #ifndef ARRAY_H_ 2 #define ARRAY_H_ 3 //Arrar.hpp 4 #include <stddef.h> 5 template <typename T, int MAXSIZE> 6 class Array 7 { 8 public: 9 //我们假设T为int型 10 typedef T value_type; //int 11 typedef T *iterator; // int*->将int* 重定义为interator 12 typedef const T* const_iterator; 13 typedef T &reference; //int& -->将int& 重定义为reference 14 typedef const T& const_reference; 15 typedef size_t size_type;//size_type常用于vector<int>::size_type 下表访问 16 17 iterator begin()//begin返回的是首地址 18 { return elems_; } 19 const_iterator begin()const 20 { return elems_; } 21 22 iterator end()//end返回的是末尾元素的下个地址 23 { return elems_+ MAXSIZE; } 24 const_iterator end()const 25 { return elems_+ MAXSIZE; } 26 27 reference operator[](size_type index)//下标访问返回的是对本身的引用 28 { return elems_[index]; } 29 const_reference operator[](size_type index)const 30 { return elems_[index]; } 31 32 size_type size()const //int->元素个数 33 { return MAXSIZE;} 34 private: 35 T elems_[MAXSIZE]; 36 }; 37
38 #endif
main.cpp:
1 #include "Array.hpp" 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 6 template <typename T> 7 void print(const T &t) 8 { 9 for(typename T::const_iterator it = t.begin(); //迭代器实现打印 10 it!= t.end(); 11 it++) 12 { 13 cout << *it << " "; 14 } 15 cout << endl; 16 } 17 18 int main(int argc, const char *argv[]) 19 { 20 Array<int, 20> arr; 21 22 for(Array<int, 20>::size_type ix =0; //下标实现初始化 23 ix != arr.size(); 24 ix ++) 25 { 26 arr[ix] = ix; 27 } 28 29 print(arr); 30 31 Array<int, 20>::const_iterator it=std::find(arr.begin(), arr.end(), 15); 32 cout << *it << endl; //标准库中的find函数 33 34 return 0; 35 }
二、智能指针:
这里我们实现了指针的一些操作, 如解引用操作符,->操作符、指针的复制与赋值。
代码如下:
SmartPtr.hpp
1 #ifndef SMARTPTR_H_ 2 #define SMARTPTR_H_ 3 4 #include <stddef.h> 5 6 template <typename T> 7 class SmartPtr 8 { 9 public: 10 SmartPtr(T *ptr= NULL ); //如果没有提供ptr的值,编译器会将其默认为NULL 11 ~SmartPtr(); 12 13 T &operator*() //解引用操作返回的是本身值的引用 14 { return *ptr_; } 15 const T &operator*()const 16 { return *ptr_; } 17 18 T *operator->() //->操作 返回的是 指针本身; 19 { return ptr_;} 20 const T *operator->()const 21 { return ptr_;} 22 23 void resetPtr(T *ptr = NULL); //将 指针重置 24 const T *getPtr()const //获取该指针 25 { return ptr_; } 26 27 private: 28 //这里我们禁用了智能指针的复制和赋值能力 29 SmartPtr(const SmartPtr&); 30 SmartPtr &operator=(const SmartPtr&); 31 32 T *ptr_; 33 }; 34 35 template <typename T> 36 SmartPtr<T>::SmartPtr(T *ptr ) 37 :ptr_(ptr) 38 { } 39 40 template <typename T> 41 SmartPtr<T>::~SmartPtr() 42 { delete ptr_; } 43 44 template <typename T> 45 void SmartPtr<T>::resetPtr(T *ptr ) 46 { 47 if(ptr_ == ptr) //如果把自己本身赋值给自己,则直接返回 48 return; 49 delete ptr_; 50 ptr_ = ptr ; 51 } 52 53 #endif
main.cpp:
1 #include "SmartPtr.hpp" 2 #include <iostream> 3 using namespace std; 4 5 class Test 6 { 7 public: 8 9 Test() {cout << "construct" << endl; } 10 ~Test(){cout << "~construct" << endl; } 11 }; 12 13 int main(int argc, const char *argv[]) 14 { 15 SmartPtr<Test> sp(new Test); 16 17 return 0; 18 }
三、Stack 及其特化:
1、这里我们揭示了Stack 的 pop、push、top、empty操作;
2、对于一些特殊的类型,如 const char*(C风格的字符串),当我们用push函数时,总会出现一些问题,原因在于:
push函数复制给定值以创建 stack中的新元素(值拷贝),而默认情况下,复制C 风格字符串只会复制其指针,不会复制字符串(衰退【decay】),这时复制指针将会出现共享指针在其他环境中会出现的所有问题(如重复析构),最严重的是,若指针指向动态内存,用户就有可能删除指针所指的数组。
1 //Stack.hpp 2 #ifndef STACK_H_ 3 #define STACK_H_ 4 5 #include <vector> 6 #include <stdexcept> 7 8 //Stack----------------------- 9 template <typename T> 10 class Stack 11 { 12 public: 13 void push(const T &t); 14 void pop(); 15 T top()const; 16 17 bool empty()const 18 { return elems_.empty(); } 19 private: 20 std::vector<T> elems_; 21 }; 22 23 template <typename T> 24 void Stack<T>::push(const T &t) 25 { 26 elems_.push_back(t); 27 } 28 29 template <typename T> 30 void Stack<T>::pop() 31 { 32 if( !elems_.empty() ) 33 elems_.pop_back(); 34 else 35 throw std::out_of_range("out of range"); 36 } 37 38 template <typename T> 39 T Stack<T>::top()const 40 { 41 if( !elems_.empty() ) 42 return elems_.back(); 43 else 44 throw std::out_of_range("out of range"); 45 } 46 //---------------------------- 47 48 //特化------------------ 49 template <> 50 class Stack<const char*> 51 { 52 public: 53 void push(const char *); 54 void pop(); 55 const std::string top()const; 56 //注意上面的函数返回的是string,为了避免管理字符数组char[] 57 bool empty()const 58 { return elems_.empty(); } 59 private: 60 std::vector<std::string> elems_; //通过这一数据元素实现以上各个功能 61 }; 62 63 void Stack<const char*>::push(const char*t) 64 { 65 elems_.push_back(t); 66 } 67 68 void Stack<const char*>::pop() 69 { 70 if( !elems_.empty() ) 71 elems_.pop_back(); 72 else 73 throw std::out_of_range("out of range"); 74 } 75 76 const std::string Stack<const char*>::top()const 77 { 78 if( !elems_.empty() ) 79 return elems_.back(); 80 else 81 throw std::out_of_range("out of range"); 82 } 83 //---------------- 84 85 #endif
main.cpp
//main.cpp #include "Stack.hpp" #include <iostream> using namespace std; int main(int argc, const char *argv[]) { try { const char *s1 = "foo"; Stack<const char *> st; st.push(s1); st.push("bar"); cout << st.top() << endl; st.pop(); cout << st.top() << endl; st.pop(); } catch(exception &e) { cout << e.what()<< endl; } return 0; }