我们在学习完模板的基本定义之后,我们就要开始用模板来解决各种问题了。我们说模板是泛型编程,那么他就可以简化我们很多的代码量,本质上就是我们的工作交给了编译器实现。接下来我们就来模拟实现一下常用模板类。
当然模拟实现之前,我们还要补充一下迭代器的定义与功能。
C++中的迭代器是一种用于遍历容器中元素的对象。它类似于指针,可以指向容器中的元素,并且可以进行自增、自减等操作。在学习初期,我们可以简单的把迭代器认为是指针。在深入学习了之后,迭代器其实是封装屏蔽底层差异和实现细节,提供统一的访问修改遍历的一种方式,待会在我们进行模拟实现的时候,我们就可以体会的到。
一.string类
string类主要针对的是字符串,他是一个储存字符串的模板类,我们可以看看他内部的功能。
这里string的使用方式我就不多说了,重点是如何模拟实现这些功能。我挑了几个重点的功能进行模拟实现。
class string
{
friend ostream& operator<<(ostream& _cout, const castle::string& s);
friend istream& operator>>(istream& _cin, castle::string& s);
public:
typedef char* iterator;
public:
void swap(char* str)
{
char* tmp = str;
str = _str;
_str = tmp;
}
string(const char* str = "")
{
(* this).reserve(strlen(str)+1);
int i = 0;
while (str[i] != '\0')
{
_str[i] = str[i];
i++;
}
_str[i] = '\0';
_size = i;
}
string(const string& s)
:_size(0),
_capacity(0),
_str (nullptr)
{
(*this).reserve(strlen(s._str) + 1);
int i = 0;
while (s._str[i] != '\0')
{
_str[i] = s._str[i];
i++;
}
_str[i] = '\0';
_size = i;
}
string& operator=(const string& s)
{
char* tmp = new char[strlen(s._str) + 1];
strcpy(tmp, s._str);
(*this).swap(tmp);
_size = s._size;
_capacity = s._capacity;
return *this;
}
~string()
{
delete[] _str;
_capacity = 0;
_size = 0;
}
//
// iterator
iterator begin()
{
return _str;
}
iterator end()
{
return &_str[_size];
}
/
// modify
void push_back(char c)
{
if (_size < _capacity)
{
_str[_size] = c;
}
else
{
(*this).reserve(1);
_str[_size] = c;
}
_size++;
_str[_size] = '\0';
}
string& operator+=(char c)
{
if (_size < _capacity-1)
{
_str[_size] = c;
}
else
{
(*this).reserve(1);
_str[_size] = c;
}
_size++;
_str[_size] = '\0';
return *this;
}
void append(const char* str)
{
const char* tmp = str;
while (*tmp != '\0')
{
*this += *tmp;
tmp++;
}
}
string& operator+=(const char* str)
{
const char* tmp = str;
while (*tmp != '\0')
{
*this += *tmp;
tmp++;
}
return *this;
}
void clear()
{
_size = 0;
}
void swap(string& s)
{
char* tmp = s._str;
s._str = _str;
_str = tmp;
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
const char* c_str()const
{
return _str;
}
/
// capacity
size_t size()const
{
int i = 0;
while (_str[i] != '\0')
{
i++;
}
return i;
}
size_t capacity()const
{
return _capacity;
}
bool empty()const
{
if (_size == 0)
return true;
else
return false;
}
void resize(size_t n, char c = '\0')
{
int size = _size;
if (n > _size)
{
if (n > _capacity)
reserve(n-size);
int i = size;
while (i < n)
{
_str[i] = c;
++i;
}
_size=n;
_str[_size] = '\0';
}
else
{
_size = n;
_str[_size] = '\0';
}
}
void reserve(size_t n)
{
if (_size == 0 && _capacity == 0)
{
char *tmp = new char[11];
_capacity = 11;
_str = tmp;
}
if (_size + n>=_capacity)
{
char* tmp = new char[2 * _capacity];
_capacity *= 2;
for (size_t i = 0; i < _size; i++)
tmp[i] = _str[i];
delete[] _str;
_str = tmp;
}
}
/
// access
char& operator[](size_t index)
{
return _str[index];
}
const char& operator[](size_t index)const
{
return _str[index];
}
/
//relational operators
bool operator<(const string& s)
{
if (strcmp(_str, s._str) == -1)
return true;
else
return false;
}
bool operator<=(const string& s)
{
if (*this < s || *this == s)
return true;
else
return false;
}
bool operator>(const string& s)
{
if (*this <= s)
return false;
else
return true;
}
bool operator>=(const string& s)
{
if (*this < s)
return false;
else
return true;
}
bool operator==(const string& s)
{
if (strcmp(_str, s._str) == 0)
return true;
else
return false;
}
bool operator!=(const string& s)
{
if (*this == s)
return false;
else
return true;
}
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
while (_str[pos] != c)
{
if (pos == _size)
break;
pos++;
}
if (pos == _size)
return 0;
else return pos;
}
// 返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const
{
char* tmp = strstr(&_str[pos], s);
if (tmp == nullptr)
return 0;
char* begin = _str;
int count = 0;
while (begin != tmp)
{
begin++;
count++;
}
return count;
}
// 在pos位置上插入字符c/字符串str,并返回该字符的位置
string& insert(size_t pos, char c)
{
*this += '\0';
size_t cur = _size-1;
while (cur != pos)
{
_str[cur + 1] = _str[cur];
cur--;
}
if (pos == _size-1)
{
_str[_size] = _str[_size-1];
_str[pos] = c;
}
else
_str[pos+1] = c;
return *this;
}
string& insert(size_t pos, const char* str)
{
size_t size = strlen(str);
for (int i = 0; i < size; ++i)
*this += '\0';
size_t cur = _size;
while (cur != pos)
{
_str[cur + 3] = _str[cur];
cur--;
}
for (int i = 0; i < size; ++i)
{
_str[pos+1] = str[i];
++pos;
}
return *this;
}
// 删除pos位置上的元素,并返回该元素的下一个位置
string& erase(size_t pos, size_t len)
{
size_t cur = pos + len;
while (cur != _size)
{
_str[cur - len] = _str[cur];
cur++;
}
_size -=len;
_str[_size] = '\0';
return *this;
}
private:
char* _str;
size_t _capacity=0;
size_t _size=0;
};
ostream& operator<<(ostream& _cout, const castle::string& s)
{
int i = 0;
while (s._str[i] != '\0')
{
_cout << s._str[i];
i++;
}
_cout << endl;
return _cout;
}
istream& operator>>(istream& _cin, castle::string& s)
{
char ch;
ch = getchar();
while (ch != '\n')
{
s += ch;
ch = getchar();
}
return _cin;
}
string里面的内容我挑了这一些来实现,我们主要要确定其内置类型,才能进行对这个类的功能进行实现,其余的无非就是对数据结构的选择,内部的操作也不是非常的难,大家可以看一下。
二.vector类
在vector中,我们对于模板的应用据更广泛了,我们来看:
template<class T>
class vector
{
public:
// Vector的迭代器是一个原生指针
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
// construct and destroy
vector()
:_start(nullptr),
_finish(nullptr),
_endOfStorage(nullptr)
{}
vector(int n, const T& value = T())
:_start(nullptr),
_finish(nullptr),
_endOfStorage(nullptr)
{
resize(n, value);
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
:_start(nullptr),
_finish(nullptr),
_endOfStorage(nullptr)
{
InputIterator it = first;
while (it != last)
{
push_back(*it);
++it;
}
}
vector(const vector<T>& v)
:_start(nullptr),
_finish(nullptr),
_endOfStorage(nullptr)
{
for (auto x : v)
push_back(x);
}
vector<T>& operator= (vector<T> v)
{
int cap= v._endOfStorage- v._start;
vector<T> tmp;
for (auto x : v)
{
tmp.push_back(x);
}
swap(tmp);
return *this;
}
~vector()
{
}
// capacity
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
void reserve(size_t n)
{
int size = _finish - _start;
int cap = _endOfStorage - _start;
if (_start == nullptr)
{
T* tmp = new T[10];
_start = tmp;
_finish = _start + 1;
_endOfStorage = _start + 10;
}
else
{
if (n >= cap)
{
T* tmp = new T[2*cap];
T* cur = tmp;
for (auto x : *this)
{
*cur = x;
cur++;
}
_start = tmp;
_finish = _start + size;
_endOfStorage = _start + 2*cap;
//swap(_start, tmp._start);
//swap(_finish, tmp._finish);
//swap(_endOfStorage, tmp._endOfStorage);
}
}
}
void resize(size_t n, const T& value = T())
{
if (_start == nullptr)
reserve(10);
int num = _endOfStorage - _start;
if (n < num)
{
_finish = _start + n + 1;
auto it = begin();
while (it != end())
{
*it = value;
it++;
}
/*for (auto x : *this)
x = value;*/
}
else
{
reserve(n);
_finish = _start + n + 1;
//for (auto x : *this)
// x = value;
auto it = begin();
while (it != end())
{
*it = value;
it++;
}
}
}
///access///
T& operator[](size_t pos)
{
return *(_start + pos);
}
const T& operator[](size_t pos)const
{
return *(_start + pos);
}
///modify/
void push_back(const T& x)
{
if (_start == nullptr)
{
reserve(1);
*_start = x;
}
else
{
if (_endOfStorage + 1 == _finish)
reserve(2 * (_endOfStorage-_start));
*_finish = x;
_finish++;
}
}
void pop_back()
{
_finish--;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
iterator insert(iterator pos, const T& x)
{
if (_endOfStorage + 1 == _finish)
reserve(5);
iterator cur = _finish;
while (cur != pos)
{
*cur = *(cur - 1);
cur--;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
iterator cur = pos;
while (cur != _finish)
{
*cur = *(cur + 1);
cur++;
}
_finish--;
return pos;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
可以看到,vector中的内置类型都变成了迭代器。其实vector的本质就是顺序表,跟string不同,他是可以对任意类型创建顺序表,实现了泛型编程,更能提现模板的重要性。
三.list类
list的本质就是带头双向循环链表,这个在数据结构中我们也实现过,我们现在在c++类中模拟实现一下,我们可以更加体会到迭代器的重要性。
namespace castle
{
// List的节点类
template<class T>
struct ListNode
{
ListNode(const T& val = T())
:_pPre(nullptr),
_pNext(nullptr),
_val(val)
{}
ListNode<T>* _pPre;
ListNode<T>* _pNext;
T _val;
};
template<class Iterator, class Ref, class Ptr>
class Reverse_iterator
{
typedef Reverse_iterator<Iterator, Ref, Ptr> Self;
Iterator _it;
public:
Reverse_iterator(Iterator it)
:_it(it)
{}
Self& operator++()
{
_it--;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_it--;
return tmp;
}
Self& operator--()
{
_it++;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_it++;
return tmp;
}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->()
{
return &(operator*());
}
bool operator!=(const Self& l)
{
return l._it != _it;
}
bool operator==(const Self& l)
{
return l._it == _it;
}
};
// vector和list反向迭代器实现
//List的迭代器类
template<class T, class Ref, class Ptr>
class ListIterator
{
public:
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
:_pNode(pNode)
{}
ListIterator(const Self& l)
{
_pNode = l._pNode;
}
Ref operator*()
{
return _pNode->_val;
}
Ptr operator->()
{
return &(_pNode->_val);
}
Self& operator++()
{
_pNode=_pNode->_pNext;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_pNode = _pNode->_pNext;
return tmp;
}
Self& operator--()
{
_pNode = _pNode->_pPre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_pNode = _pNode->_pPre;
return tmp;
}
bool operator!=(const Self& l)
{
return l._pNode != _pNode;
}
bool operator==(const Self& l)
{
return l._pNode == _pNode;
}
PNode _pNode;
};
//list类
template<class T>
class list
{
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
public:
///
// List的构造
list()
{
CreateHead();
}
list(int n, const T& value = T())
{
CreateHead();
while (n != 0)
{
push_back(value);
n--;
}
}
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
iterator it = first;
while (it != last)
{
push_back(*it);
it++;
}
}
list(const list<T>& l)
{
CreateHead();
auto it = l.begin();
while (it != l.end())
{
push_back(*it);
it++;
}
}
list<T>& operator=(const list<T> l)
{
list<T> tmp;
auto it = l.begin();
while (it != l.end())
{
tmp.push_back(*it);
it++;
}
swap(tmp);
return *this;
}
~list()
{
}
///
// List Iterator
iterator begin()
{
return iterator(_pHead->_pNext);
}
iterator end()
{
return iterator(_pHead);
}
const_iterator begin() const
{
return const_iterator(_pHead->_pNext);
}
const_iterator end() const
{
return const_iterator(_pHead);
}
reverse_iterator cbegin()
{
return reverse_iterator(end());
}
reverse_iterator cend()
{
return reverse_iterator(begin());
}
const_reverse_iterator cbegin() const
{
return const_reverse_iterator(end());
}
const_reverse_iterator cend() const
{
return const_reverse_iterator(begin());
}
///
// List Capacity
size_t size()const
{
size_t i = 0;
PNode cur = _pHead->_pNext;
while (cur != _pHead)
{
cur=cur->_pNext;
i++;
}
return i;
}
bool empty()const
{
return _pHead->_pNext == _pHead;
}
// List Access
T& front()
{
return _pHead->_pNext->_val;
}
const T& front()const
{
return _pHead->_pNext->_val;
}
T& back()
{
return _pHead->_pPre->_val;
}
const T& back()const
{
return _pHead->_pPre->_val;
}
// List Modify
void push_back(const T& val)
{
insert(end(), val);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
Node* newnode = new Node;
newnode->_val = val;
newnode->_pNext = pos._pNode;
newnode->_pPre = pos._pNode->_pPre;
newnode->_pPre->_pNext = newnode;
pos._pNode->_pPre = newnode;
return pos._pNode->_pPre;
}
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
pos._pNode->_pPre->_pNext = pos._pNode->_pNext;
pos._pNode->_pNext->_pPre = pos._pNode->_pPre;
PNode ret = pos._pNode->_pNext;
delete pos._pNode;
return ret;
}
void clear()
{
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
}
void swap(list<T>& l)
{
std::swap(_pHead, l._pHead);
}
void CreateHead()
{
_pHead = new Node;
_pHead->_pNext = _pHead;
_pHead->_pPre = _pHead;
_pHead->_val = 0;
}
private:
PNode _pHead;
};
在castle命名空间里,我们实现了多个类,有节点类,有迭代器类,有链表类,我们要围绕着链表类来依靠其他类来做补充,其中最难的是迭代器类,我们可以看到定义了正反向迭代器,其实原理是一样的,但是实现会比vector更加复杂一些,它涉及了返回节点指针,返回节点值和值的指针,使用大家在实现的时候要注意小细节。
这就是三个类的全部实现,大家可以看着我的代码来自己也模拟实现一下!