STL 之 vector源代码实现(云算法<< [] = 重载, new delete,throw catch)
2014-10-08 21:51
447 查看
小结:
(1) 异常类,try -- throw -- catch 的应用:检验空间是否申请成功了;数组边界处理,越界处理报错,throw 异常类的默认构造函数,catch后用异常类的对象调用其show_message()成员函数进行具体异常显示。
(2)algorithm 之 copy()的原型:
STL algorithm之copy template <class InputIterator, class OutputIterator>OutputIterator copy ( InputIterator first, InputIterator last,
OutputIteratorresult );作用:将
[first,last)范围的元素,拷贝到以result开始的范围内。类似于:memcopy()
(3)运算符重载:/ const int&operator[](const size_t)const;
第一个const说的是返回值,返回的是一个常量引用,不能修改 第二个const是一个参数,表示在函数内不会修改这个参数 最后一个const是表示this指针指向的是const 也
就是在这个函数内,这个类所有成员都相当于是const
运算符重载功能不允许我们使用新的运算符,也不允许我们改变运算符的优先级,因此运算符的重载版本在计算表达式的值时优先级与原来的基本运算符相同。
(4)运算符重载 之 参数的个数:
1.重载为成员函数时:
双目运算符仅有一个参数;对单目运算符,不能再显式说明参数。重载为成员函数时,总时隐含了一个参数,该参数是this指针,它是指向调用该成员函数对象的指针
2. 重载为友元函数:
运算符重载函数还可以为友元函数。当重载友元函数时,将没有隐含的参数this指针。这样,对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。 但是,有些运行符不能重载为友元函数,它们是:=,(),[]和->。
(5)运算符重载的方法:
对同一个运算符号,往往可以通过普通函数、友员函数和类成员函数这三种方式实现重载,以完成同样的功能。通过普通函数实现运算符重载的特点是自定义类不得不将其成员变量公开,以便让普通函数可以访问类的成员变量,这破坏了类的封装性,所以这种重载方式要少用或不用。C++语言之所以提供此种方式,是为了与C语言兼容。通过友员函数重载运算符的特点可以不破坏类的封装性,类的成员变量可以是私有的,但这种方式需要在类中定义友员函数,以允许友员函数可以操作类的私有成员变量,这在实际使用中也很不方便,所以不在必要时不要使用,这里的必要指的是C++中有一些运算符不能用类成员函数的方式实现重载,比如用于cout和cin的流提取符就必须使用友员函数实现重载。
通过类成员函数重载运算符是我们推荐使用的,运算符重载函数是类的成员函数,正好满足了类的封装性要求。
(6)重载运算符坚持4个“不能改变”:
不能改变运算符操作数的个数;不能改变运算符原有的优先级;
不能改变运算符原有的结合性;不能改变运算符原有的语法结构。
(7)为什么只能将重载"<<"和">>"的函数作为友元函数或普通函数,而不能将它们定义为成员函数
<<有两个参数,一个是输出流对象(我们常用的cout),还有就是要输出的东西。
例如:cout<<"haha";也就是说<<的第一个参数必须是输出流对象。在成员函数里实现<<重载,
我们知道this会作为第一个参数,而这是不符合要求的。
(8)指针当做数组用:
如果你仅仅是定义了个char *p;然后就去用p[3] ,p[4],显然p是个野指针!指向不确定!这种做法是错误的!正确的用法: char a[10]="asdas"; p=a; 然后就可以p[3] 等价于a3] 或者 int *pa = new int[5]; p[3]也是可以的,因为你动态申请了数组,跟 int pa[5]差不多(如下文的)
/**** overload operator [] ****/
一:vector异常类 Myexcep.h
二:vector 类的代码 vec.h
三 vec.h 的实现和main 函数 Vec,cpp
四 知识补充 —— vector类常用的函数如下所示:
vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组。像数组一样,vector类也用从0开始的下标表示元素的位置;但和数组不同的是,当vector对象创建后,数组的元素个数会随着vector对象元素个数的增大和缩小而自动变化。
1.构造函数
vector():创建一个空vector
vector(int nSize):创建一个vector,元素个数为nSize
vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
vector(const vector&):复制构造函数
vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector
2.增加函数
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
3.删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
[b]4.遍历函数
[/b]
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
5.判断函数
bool empty() const:判断向量是否为空,若为空,则向量中无元
6.大小函数
int size() const:返回向量中元素的个数
int capacity() const:返回当前向量张红所能容纳的最大元素值
int max_size() const:返回最大可允许的vector元素数量值
7.其他函数
void swap(vector&):交换两个同类型向量的数据
void assign(int n,const T& x):设置向量中第n个元素的值为x
void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
(1) 异常类,try -- throw -- catch 的应用:检验空间是否申请成功了;数组边界处理,越界处理报错,throw 异常类的默认构造函数,catch后用异常类的对象调用其show_message()成员函数进行具体异常显示。
(2)algorithm 之 copy()的原型:
STL algorithm之copy template <class InputIterator, class OutputIterator>OutputIterator copy ( InputIterator first, InputIterator last,
OutputIteratorresult );作用:将
[first,last)范围的元素,拷贝到以result开始的范围内。类似于:memcopy()
(3)运算符重载:/ const int&operator[](const size_t)const;
第一个const说的是返回值,返回的是一个常量引用,不能修改 第二个const是一个参数,表示在函数内不会修改这个参数 最后一个const是表示this指针指向的是const 也
就是在这个函数内,这个类所有成员都相当于是const
运算符重载功能不允许我们使用新的运算符,也不允许我们改变运算符的优先级,因此运算符的重载版本在计算表达式的值时优先级与原来的基本运算符相同。
(4)运算符重载 之 参数的个数:
1.重载为成员函数时:
双目运算符仅有一个参数;对单目运算符,不能再显式说明参数。重载为成员函数时,总时隐含了一个参数,该参数是this指针,它是指向调用该成员函数对象的指针
2. 重载为友元函数:
运算符重载函数还可以为友元函数。当重载友元函数时,将没有隐含的参数this指针。这样,对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。 但是,有些运行符不能重载为友元函数,它们是:=,(),[]和->。
(5)运算符重载的方法:
对同一个运算符号,往往可以通过普通函数、友员函数和类成员函数这三种方式实现重载,以完成同样的功能。通过普通函数实现运算符重载的特点是自定义类不得不将其成员变量公开,以便让普通函数可以访问类的成员变量,这破坏了类的封装性,所以这种重载方式要少用或不用。C++语言之所以提供此种方式,是为了与C语言兼容。通过友员函数重载运算符的特点可以不破坏类的封装性,类的成员变量可以是私有的,但这种方式需要在类中定义友员函数,以允许友员函数可以操作类的私有成员变量,这在实际使用中也很不方便,所以不在必要时不要使用,这里的必要指的是C++中有一些运算符不能用类成员函数的方式实现重载,比如用于cout和cin的流提取符就必须使用友员函数实现重载。
通过类成员函数重载运算符是我们推荐使用的,运算符重载函数是类的成员函数,正好满足了类的封装性要求。
(6)重载运算符坚持4个“不能改变”:
不能改变运算符操作数的个数;不能改变运算符原有的优先级;
不能改变运算符原有的结合性;不能改变运算符原有的语法结构。
(7)为什么只能将重载"<<"和">>"的函数作为友元函数或普通函数,而不能将它们定义为成员函数
<<有两个参数,一个是输出流对象(我们常用的cout),还有就是要输出的东西。
例如:cout<<"haha";也就是说<<的第一个参数必须是输出流对象。在成员函数里实现<<重载,
我们知道this会作为第一个参数,而这是不符合要求的。
(8)指针当做数组用:
如果你仅仅是定义了个char *p;然后就去用p[3] ,p[4],显然p是个野指针!指向不确定!这种做法是错误的!正确的用法: char a[10]="asdas"; p=a; 然后就可以p[3] 等价于a3] 或者 int *pa = new int[5]; p[3]也是可以的,因为你动态申请了数组,跟 int pa[5]差不多(如下文的)
/**** overload operator [] ****/
一:vector异常类 Myexcep.h
#include<string> #include<iostream> using namespace std; class Myexcep { public: Myexcep() :m_exnote("Get a exception ") {} Myexcep(const string &other){m_exnote = other;} virtual ~Myexcep(){} virtual void show_message() {cout << m_exnote <<endl;} private: string m_exnote; }; class Outofbond :public Myexcep { public: Outofbond() :m_outnote("Get a Out of bond exception ") {} Outofbond(const string &other){m_outnote = other;} ~Outofbond(){} void show_message(){cout << m_outnote <<endl;} private: string m_outnote; }; class Allocfail :public Myexcep { public: Allocfail():m_alonote("Get a Allocate fail exception "){} Allocfail(const string &other){m_alonote = other;} ~Allocfail(){} void show_message(){cout << m_alonote <<endl;} private: string m_alonote; };
二:vector 类的代码 vec.h
#ifndef VEC_H_H #define VEC_H_H #include "Myexce.h" #include<cstdio> #include<iostream> #include<algorithm> #include<cassert> using namespace std; template <class T> class Vec { public: typedef T* iterator; typedef const T* const_iterator; typedef size_t size_type; typedef T value_type; public: Vec(); Vec(size_type,const T&); Vec(const Vec &); Vec& operator=(const Vec&); ~Vec();//调用相应的create()和uncreate()函数 T& operator[](size_type index); const T& operator[](size_type index) const;// 运算符重载 void push_back(const T&); void pop_back(); void erase(const size_type&);//根据下标删除元素,push_back()调用了grow() size_type size() const {return (m_finished - m_start);} iterator begin() {return m_start;} const_iterator begin() const {return m_start;} iterator end() {return m_finished;} const_iterator end() const {return m_finished;} private: void create(); void create(size_type,const T&); void create(const_iterator,const_iterator);//调用allocate()申请空间,并调用init_fill(),init_copy()进行初始化 void uncreate(); T* allocate(size_type); void init_fill(iterator,iterator,const T&); void init_copy(const_iterator,const_iterator,iterator); void grow();// 调用了size(),和 max() void append_element(const T&); private: iterator m_start; iterator m_finished; iterator m_limit;// 有这么多指针,肯定有深拷贝 }; #endif
三 vec.h 的实现和main 函数 Vec,cpp
//---------------------vec.cpp------------- #include "vec.h" /**** constructor ****/ template <class T> Vec<T>::Vec() { create(); } template <class T> Vec<T>::Vec(size_type sz,const T& val) { create(sz,val); } template <class T> Vec<T>::Vec(const Vec &rhs) { create(rhs.begin(),rhs.end()); } template <class T> Vec<T>& Vec<T>::operator=(const Vec& rhs) { if(&rhs == this) return *this; uncreate(); create(rhs.begin(),rhs.end()); return *this; } template <class T> Vec<T>::~Vec() { uncreate(); } /**** we have a create function to inital the data ****/ template <class T> void Vec<T>::create() { m_start = m_finished = m_limit = NULL; } template <class T> void Vec<T>::create(size_type sz,const T&val) { m_start = allocate(sz); m_finished = m_limit = m_start+sz; init_fill(m_start,m_limit,val); } template <class T> void Vec<T>::create(const_iterator first,const_iterator end) { size_type sz = end - first; m_start = allocate(sz); m_finished = m_limit = m_start+sz; init_copy(first,end,m_start); } template <class T> void Vec<T>::uncreate() { iterator iter = m_start; iterator end = m_limit; for(; iter != end; ) { iterator next_iter = iter + 1; delete(iter); iter = next_iter; } m_start = m_finished =m_limit =0; } /**** we define a function to allocate memory ****/ template <class T> T* Vec<T>::allocate(size_type sz) { T* t = new T[sizeof(T) * sz]; if(!t) { throw Allocfail(); } return t; } template <class T> void Vec<T>::init_fill(iterator data,iterator limit,const T& val) { iterator iter = data; iterator end = limit; for(; iter != end; iter++) { *iter = val; } } template <class T> void Vec<T>::init_copy(const_iterator first,const_iterator end,iterator lhs) { copy(first,end,lhs);// copy的实现暂时没有找到呢。。。 } // STL algorithm之copy template <class InputIterator, class OutputIterator> OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result ); //作用:将[first, last)范围的元素,拷贝到以result开始的范围内。类似于:memcopy() /**** overload operator [] ****/ template <class T> T& Vec<T>::operator[](size_type index) { if(index >= size()) { throw Outofbond(); } return m_start[index]; } template <class T> const T& Vec<T>::operator[](size_type index) const { if(index >= size()) { throw Outofbond(); } return m_start[index]; } /**** push_back ,pop_back,erase ****/ template <class T> void Vec<T>::push_back(const T& val) { if(m_finished == m_limit) grow(); append_element(val); } template <class T> void Vec<T>::pop_back() { if(size() == 0) return ; m_finished--; } template <class T> void Vec<T>::erase(const size_type& ipos) { if(ipos <0 || ipos >size()) { throw Outofbond(); } size_type iend = size()-1; size_type i = ipos; for(;i >= ipos && i < iend ; i++) { m_start[i] = m_start[i+1]; }// 后面的元素依次向前移动,只能删除一个 m_finished--; } template <class T> void Vec<T>::append_element(const T& val) { assert(m_finished!=m_start); *m_finished++ = val; } inline size_t max(const size_t lhs,const size_t rhs) { return lhs > rhs ? lhs:rhs; } template <class T> void Vec<T>::grow() { size_type new_size = max( 2*size(), 1); iterator new_start = allocate(new_size); iterator new_limit = new_start + new_size; iterator new_finished = new_start + size(); init_copy(begin(),end(),new_start); uncreate(); m_start = new_start; m_finished = new_finished; m_limit = new_limit; } /**** output the vector ****/ template <class T> ostream& operator<<(ostream &os, const Vec<T> &me) { const T* iter = me.begin(); //Is "const T*" replaced by "const_iterator"? for(;iter != me.end(); iter++) { os << *iter <<", "; } return os; } /**** test the case ****/ int main() { try { cout << "Test begin: " << endl; Vec<int> v1(4,3); cout << "After v1(4,3), v1[3]: " << v1[3] <<endl; Vec<int> v2(v1); cout << "After v2(v1), v2--value: " << v2 <<endl; Vec<int> v3; v3 = v2; cout << "After v3=v2, v3--value: " << v3 <<endl; v3.pop_back(); cout << "After v3.pop_back(), v3--value: " << v3 <<endl; v3.push_back(5); cout << "After v3.push_back(5), v3--value: " << v3 <<endl; Vec<double> v4(5, 222.2); cout << "After v4(5,222.2),v4--value:" << v4 << endl; Vec<char> v5(5, 'a'); cout << "After v5(5,222.2),v5--value:" << v5 << endl; string aa = "hi world"; // string bb = aa; // cout << bb << endl; Vec<string> v6(5, aa); v6.push_back("hello 好"); cout << v6 << endl; Vec<string> v7; v7 = v6; cout << v7[4] << endl; v3.erase(2); cout << "After v3.erase(2), v3--value: " << v3 <<endl; cout << "After v3.erase(2), v3--value: " << v3[6] <<endl; } catch(Outofbond e) { e.show_message(); exit(-1); } catch(Allocfail e){ e.show_message(); exit(-1); } return 0; }
四 知识补充 —— vector类常用的函数如下所示:
vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组。像数组一样,vector类也用从0开始的下标表示元素的位置;但和数组不同的是,当vector对象创建后,数组的元素个数会随着vector对象元素个数的增大和缩小而自动变化。
1.构造函数
vector():创建一个空vector
vector(int nSize):创建一个vector,元素个数为nSize
vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
vector(const vector&):复制构造函数
vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector
2.增加函数
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
3.删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
[b]4.遍历函数
[/b]
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
5.判断函数
bool empty() const:判断向量是否为空,若为空,则向量中无元
6.大小函数
int size() const:返回向量中元素的个数
int capacity() const:返回当前向量张红所能容纳的最大元素值
int max_size() const:返回最大可允许的vector元素数量值
7.其他函数
void swap(vector&):交换两个同类型向量的数据
void assign(int n,const T& x):设置向量中第n个元素的值为x
void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
相关文章推荐
- 重载一个+运算符、<<运算符和>运算符。实现对分数的运算
- 用char*实现的一个完整的类,包含类的基本操作:一般构造、拷贝构造、赋值转换、重载 > >,< <
- 为 vector 重载 << (输出操作符)
- STL(3)---<vector>
- 《C++第九周实验报告1-1》--------接第8周任务1,定义Complex类中的<<和>>运算符的重载,实现输入和输出
- <vector> template实现
- C++ Greedy Snake的OOP实现 贪食蛇 <list> STL初次学习
- &lt;Effective STL&gt;笔记--vector和string
- (zz)对cout << 重载的源代码
- 第九周试验任务1--定义Time类中的<<和>>运算符的重载,实现输入和输出。
- 一种排序 set<stl> 无重复 + < 符号重载 ==
- [置顶] ART异常处理机制(4) - throw & catch & finally实现
- STL容器中的vector<摘自别人博客>
- 用vector<int>对象元素,实现输入10数,将每个奇数值元素用该值的两倍替换
- 第九周实验任务二--定义Complex类中的<<和>>运算符的重载,实现输入和输出,使程序读起来更自然
- 11/7/2 STL vector<T> (2)
- STL容器之vector<bool>
- STL的vector<string>的初始化方式总结
- 用char*实现的一个完整的类,包含类的基本操作:一般构造、拷贝构造、赋值转换、重载 > >,< <
- 对cout << 重载的源代码