在 C++ 中为我自己的自定义矢量模板 class 实现一个迭代器(类似于来自 STL 的东西)
implementing an iterator (something like from STL) for my own custom vector template class in C++
我有一个来自 GeeksforGeeks 网站的自己的容器,我从那里获得了下面的容器代码。我喜欢创建一个迭代器 class,它的功能将使我能够使用 for
循环和功能,例如在我的容器中开始和结束,而 for 循环将类似于
MyClassForIterator iter;
for(iter=mycontainer_items_obj.begin();iter!=mycontainer_items_obj.end();iter++)
{
cout<<*iter<<endl
...
}
我想知道这在 C++ 中是否可行以及如何实现?
矢量模板class
#include <bits/stdc++.h>
using namespace std;
template <typename T> class vectorClass
{
// arr is the integer pointer
// which stores the address of our vector
T* arr;
// capacity is the total storage
// capacity of the vector
int capacity;
// current is the number of elements
// currently present in the vector
int current;
public:
// Default constructor to initialise
// an initial capacity of 1 element and
// allocating storage using dynamic allocation
vectorClass()
{
arr = new T[1];
capacity = 1;
current = 0;
}
// Function to add an element at the last
void push(T data)
{
// if the number of elements is equal to the
// capacity, that means we don't have space to
// accommodate more elements. We need to double the
// capacity
if (current == capacity) {
T* temp = new T[2 * capacity];
// copying old array elements to new array
for (int i = 0; i < capacity; i++) {
temp[i] = arr[i];
}
// deleting previous array
delete[] arr;
capacity *= 2;
arr = temp;
}
// Inserting data
arr[current] = data;
current++;
}
// function to add element at any index
void push(int data, int index)
{
// if index is equal to capacity then this
// function is same as push defined above
if (index == capacity)
push(data);
else
arr[index] = data;
}
// function to extract element at any index
T get(int index)
{
// if index is within the range
if (index < current)
return arr[index];
}
// function to delete last element
void pop() { current--; }
// function to get size of the vector
int size() { return current; }
// function to get capacity of the vector
int getcapacity() { return capacity; }
// function to print array elements
void print()
{
for (int i = 0; i < current; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
};
// Driver code
int main()
{
vectorClass<int> v;
vectorClass<char> v1;
v.push(10);
v.push(20);
v.push(30);
v.push(40);
v.push(50);
v1.push(71);
v1.push(72);
v1.push(73);
v1.push(74);
cout << "Vector size : " << v.size() << endl;
cout << "Vector capacity : " << v.getcapacity() << endl;
cout << "Vector elements : ";
v.print();
v.push(100, 1);
cout << "\nAfter updating 1st index" << endl;
cout << "Vector elements of type int : " << endl;
v.print();
// This was possible because we used templates
cout << "Vector elements of type char : " << endl;
v1.print();
cout << "Element at 1st index of type int: " << v.get(1)
<< endl;
cout << "Element at 1st index of type char: "
<< v1.get(1) << endl;
v.pop();
v1.pop();
cout << "\nAfter deleting last element" << endl;
cout << "Vector size of type int: " << v.size() << endl;
cout << "Vector size of type char: " << v1.size()
<< endl;
cout << "Vector capacity of type int : "
<< v.getcapacity() << endl;
cout << "Vector capacity of type char : "
<< v1.getcapacity() << endl;
cout << "Vector elements of type int: ";
v.print();
cout << "Vector elements of type char: ";
v1.print();
return 0;
}
是的,在 C++ 中完全可行,只需在向量中定义一个嵌套迭代器 class。这里我定义了一个前向迭代器,对于你的情况你可能想选择一个不同的类别:
template <typename T> class vectorClass
{
T* arr;
int capacity;
int current;
public:
struct iterator
{
// You need these tags to provide introspection and conform
// to standard implementations of iterators. If you were
// using Boost to define your iterator, you'd define those in
// the base class.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
iterator& operator++() { m_ptr++; return *this; }
// Postfix increment
iterator operator++(int)
{ Iterator tmp = *this; ++(*this); return tmp; }
friend bool operator== (const Iterator& a, const Iterator& b)
{ return a.m_ptr == b.m_ptr; };
friend bool operator!= (const Iterator& a, const Iterator& b)
{ return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
// Add begin/end functions to your class
iterator begin() { return iterator(arr); }
iterator end() { return iterator(arr + curr); }
/*
REST of the class remains the same
*/
};
您可能已经在评论中注意到,我提到 boost iterator facade library 作为定义迭代器的工具。如果这是您的选择,您可以使用它来消除大部分样板文件。
如果您的容器在内部将其数据存储为 contiguios 数组(就像您的一样),那么您只需使用 pointer 作为您的迭代器:
template <typename T> class vectorClass
{
public:
T* begin() { return arr; }
T* end() { return arr + current; }
T const* begin() const { return arr; }
T const* end() const { return arr + current; }
// ... etc...
};
这是可行的,因为 指针 满足 迭代器 的所有要求。事实上迭代器是指针的泛化。
我有一个来自 GeeksforGeeks 网站的自己的容器,我从那里获得了下面的容器代码。我喜欢创建一个迭代器 class,它的功能将使我能够使用 for
循环和功能,例如在我的容器中开始和结束,而 for 循环将类似于
MyClassForIterator iter;
for(iter=mycontainer_items_obj.begin();iter!=mycontainer_items_obj.end();iter++)
{
cout<<*iter<<endl
...
}
我想知道这在 C++ 中是否可行以及如何实现?
矢量模板class
#include <bits/stdc++.h>
using namespace std;
template <typename T> class vectorClass
{
// arr is the integer pointer
// which stores the address of our vector
T* arr;
// capacity is the total storage
// capacity of the vector
int capacity;
// current is the number of elements
// currently present in the vector
int current;
public:
// Default constructor to initialise
// an initial capacity of 1 element and
// allocating storage using dynamic allocation
vectorClass()
{
arr = new T[1];
capacity = 1;
current = 0;
}
// Function to add an element at the last
void push(T data)
{
// if the number of elements is equal to the
// capacity, that means we don't have space to
// accommodate more elements. We need to double the
// capacity
if (current == capacity) {
T* temp = new T[2 * capacity];
// copying old array elements to new array
for (int i = 0; i < capacity; i++) {
temp[i] = arr[i];
}
// deleting previous array
delete[] arr;
capacity *= 2;
arr = temp;
}
// Inserting data
arr[current] = data;
current++;
}
// function to add element at any index
void push(int data, int index)
{
// if index is equal to capacity then this
// function is same as push defined above
if (index == capacity)
push(data);
else
arr[index] = data;
}
// function to extract element at any index
T get(int index)
{
// if index is within the range
if (index < current)
return arr[index];
}
// function to delete last element
void pop() { current--; }
// function to get size of the vector
int size() { return current; }
// function to get capacity of the vector
int getcapacity() { return capacity; }
// function to print array elements
void print()
{
for (int i = 0; i < current; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
};
// Driver code
int main()
{
vectorClass<int> v;
vectorClass<char> v1;
v.push(10);
v.push(20);
v.push(30);
v.push(40);
v.push(50);
v1.push(71);
v1.push(72);
v1.push(73);
v1.push(74);
cout << "Vector size : " << v.size() << endl;
cout << "Vector capacity : " << v.getcapacity() << endl;
cout << "Vector elements : ";
v.print();
v.push(100, 1);
cout << "\nAfter updating 1st index" << endl;
cout << "Vector elements of type int : " << endl;
v.print();
// This was possible because we used templates
cout << "Vector elements of type char : " << endl;
v1.print();
cout << "Element at 1st index of type int: " << v.get(1)
<< endl;
cout << "Element at 1st index of type char: "
<< v1.get(1) << endl;
v.pop();
v1.pop();
cout << "\nAfter deleting last element" << endl;
cout << "Vector size of type int: " << v.size() << endl;
cout << "Vector size of type char: " << v1.size()
<< endl;
cout << "Vector capacity of type int : "
<< v.getcapacity() << endl;
cout << "Vector capacity of type char : "
<< v1.getcapacity() << endl;
cout << "Vector elements of type int: ";
v.print();
cout << "Vector elements of type char: ";
v1.print();
return 0;
}
是的,在 C++ 中完全可行,只需在向量中定义一个嵌套迭代器 class。这里我定义了一个前向迭代器,对于你的情况你可能想选择一个不同的类别:
template <typename T> class vectorClass
{
T* arr;
int capacity;
int current;
public:
struct iterator
{
// You need these tags to provide introspection and conform
// to standard implementations of iterators. If you were
// using Boost to define your iterator, you'd define those in
// the base class.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
iterator& operator++() { m_ptr++; return *this; }
// Postfix increment
iterator operator++(int)
{ Iterator tmp = *this; ++(*this); return tmp; }
friend bool operator== (const Iterator& a, const Iterator& b)
{ return a.m_ptr == b.m_ptr; };
friend bool operator!= (const Iterator& a, const Iterator& b)
{ return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
// Add begin/end functions to your class
iterator begin() { return iterator(arr); }
iterator end() { return iterator(arr + curr); }
/*
REST of the class remains the same
*/
};
您可能已经在评论中注意到,我提到 boost iterator facade library 作为定义迭代器的工具。如果这是您的选择,您可以使用它来消除大部分样板文件。
如果您的容器在内部将其数据存储为 contiguios 数组(就像您的一样),那么您只需使用 pointer 作为您的迭代器:
template <typename T> class vectorClass
{
public:
T* begin() { return arr; }
T* end() { return arr + current; }
T const* begin() const { return arr; }
T const* end() const { return arr + current; }
// ... etc...
};
这是可行的,因为 指针 满足 迭代器 的所有要求。事实上迭代器是指针的泛化。