如何扩展 vector class 及其迭代器 C++ 的功能
How to extend the functionality of vector class as well as its iterator C++
我想找到一种干净的方法来稍微改变 std::vector 的操作方式。
问题背景
我需要能够在指针基本上向后滑动的向量中有索引,例如;如果我的向量包含 {0,1,2,3,4,5} 并且索引 [3] 需要滑动,则在遍历向量时它应该 return: 0, 1, 2, 3, 3, 4 , 5
问题
在不重写整个向量 class 并实现我的更改的情况下,是否可以将 std::vector<T>
继承到自定义 class 中,并覆盖迭代器 ++ 运算符的行为作为以及 vector::begin()? (为了记住它已经滑了一个并且不会再滑了)
我试过的
到目前为止我已经尝试了一个基本的实现,但是在尝试覆盖 begin() 函数时卡住了。
#include <vector>
#include <iostream>
#include <iterator>
template <typename T>
class myVector : public std::vector<T>{
public:
class myIterator : public std::vector<T>::iterator
{
// call vector's iterotor constructor
//override
// iterator& operator++(void){}
// iterator operator++(int){}
};
using std::vector<T>::vector; // use the constructor from vector
// extend the begin function, but include original operation
myVector::myIterator begin() const
{
std::cout << "hi\n"; // testing to see if begin has been overriden properly
return std::vector<T>::begin();
}
};
// print out the vector
template <typename T>
std::ostream& operator<<(std::ostream& os, const myVector<T>& v)
{
auto begin=v.begin();
while (begin!=v.end())
{
os << *begin;
++begin;
if(begin!=v.end())
{
os << ',';
}
}
return os;
}
int main() {
myVector<int> vec = {1,2,3,4};
std::cout << vec << '\n';
}
如果你有其他干净的解决方案,也欢迎。
谢谢
我永远不会公开继承 std::vector
。它太容易被错误使用,而且您无法控制滥用。 std::vector
没有虚拟析构函数!
迭代器似乎是合适的定制点。获得一个完全兼容的迭代器还需要更多,但这对于一个工作示例来说已经足够了:
#include <iterator>
#include <vector>
#include <iostream>
template <typename It>
struct slippery_iterator {
bool slipped = false;
It to_be_repeated;
It iterator;
slippery_iterator(It iterator,It to_be_repeated) : iterator(iterator),to_be_repeated(to_be_repeated){}
slippery_iterator& operator++(){
if (!slipped && iterator == to_be_repeated){
slipped = true;
return *this;
}
++iterator;
return *this;
}
typename std::iterator_traits<It>::reference operator*(){
return *iterator;
}
bool operator!=(It other) { return iterator != other;}
};
template <typename It>
slippery_iterator<It> make_slippery_iterator(It it,It slip){
return {it,slip};
}
int main() {
std::vector<int> x{1,2,3,4,5};
auto begin = make_slippery_iterator(x.begin(),x.begin()+2);
for (; begin != x.end(); ++begin){
std::cout << *begin;
}
}
输出:
123345
PS:请注意,我习惯于 C++11,您需要 make_x
帮助器。更新的标准不需要它。
正如其他人所说,只需定义一个自定义迭代器即可。如果你还想要漂亮的范围迭代,那么你可以定义一个自定义范围 class 返回你的自定义迭代器。
查看下面的工作示例(需要 --std=c++17):
#include <vector>
#include <iostream>
template<typename T>
class SlipIterator {
private:
using iterator = typename std::vector<T>::const_iterator;
iterator i;
iterator slip;
bool has_slipped;
public:
SlipIterator(iterator i, iterator slip): i(i), slip(slip), has_slipped(false) {}
SlipIterator &operator++() {
if ((!has_slipped) && (i == slip))
has_slipped = true;
else
++i;
return *this;
}
bool operator!=(SlipIterator<T> &the_end) const { return i != the_end.i; }
const T &operator*() const { return *i; }
};
template<typename T>
class SlipperyRange {
private:
const std::vector<T> &v;
size_t slip_index;
public:
SlipperyRange(const std::vector<T> &v, size_t slip_index) : v(v), slip_index(slip_index) {}
SlipIterator<T> begin() const { return SlipIterator<T>(v.cbegin(), v.cbegin() + slip_index); }
SlipIterator<T> end() const { return SlipIterator<T>(v.cend(), v.cend()); }
};
int main() {
std::vector<int> v{1,2,3,4,5};
for(const int i: SlipperyRange{v, 2})
std::cout << i << ' ';
std::cout << '\n';
return 0;
}
我想找到一种干净的方法来稍微改变 std::vector 的操作方式。
问题背景
我需要能够在指针基本上向后滑动的向量中有索引,例如;如果我的向量包含 {0,1,2,3,4,5} 并且索引 [3] 需要滑动,则在遍历向量时它应该 return: 0, 1, 2, 3, 3, 4 , 5
问题
在不重写整个向量 class 并实现我的更改的情况下,是否可以将 std::vector<T>
继承到自定义 class 中,并覆盖迭代器 ++ 运算符的行为作为以及 vector::begin()? (为了记住它已经滑了一个并且不会再滑了)
我试过的
到目前为止我已经尝试了一个基本的实现,但是在尝试覆盖 begin() 函数时卡住了。
#include <vector>
#include <iostream>
#include <iterator>
template <typename T>
class myVector : public std::vector<T>{
public:
class myIterator : public std::vector<T>::iterator
{
// call vector's iterotor constructor
//override
// iterator& operator++(void){}
// iterator operator++(int){}
};
using std::vector<T>::vector; // use the constructor from vector
// extend the begin function, but include original operation
myVector::myIterator begin() const
{
std::cout << "hi\n"; // testing to see if begin has been overriden properly
return std::vector<T>::begin();
}
};
// print out the vector
template <typename T>
std::ostream& operator<<(std::ostream& os, const myVector<T>& v)
{
auto begin=v.begin();
while (begin!=v.end())
{
os << *begin;
++begin;
if(begin!=v.end())
{
os << ',';
}
}
return os;
}
int main() {
myVector<int> vec = {1,2,3,4};
std::cout << vec << '\n';
}
如果你有其他干净的解决方案,也欢迎。
谢谢
我永远不会公开继承 std::vector
。它太容易被错误使用,而且您无法控制滥用。 std::vector
没有虚拟析构函数!
迭代器似乎是合适的定制点。获得一个完全兼容的迭代器还需要更多,但这对于一个工作示例来说已经足够了:
#include <iterator>
#include <vector>
#include <iostream>
template <typename It>
struct slippery_iterator {
bool slipped = false;
It to_be_repeated;
It iterator;
slippery_iterator(It iterator,It to_be_repeated) : iterator(iterator),to_be_repeated(to_be_repeated){}
slippery_iterator& operator++(){
if (!slipped && iterator == to_be_repeated){
slipped = true;
return *this;
}
++iterator;
return *this;
}
typename std::iterator_traits<It>::reference operator*(){
return *iterator;
}
bool operator!=(It other) { return iterator != other;}
};
template <typename It>
slippery_iterator<It> make_slippery_iterator(It it,It slip){
return {it,slip};
}
int main() {
std::vector<int> x{1,2,3,4,5};
auto begin = make_slippery_iterator(x.begin(),x.begin()+2);
for (; begin != x.end(); ++begin){
std::cout << *begin;
}
}
输出:
123345
PS:请注意,我习惯于 C++11,您需要 make_x
帮助器。更新的标准不需要它。
正如其他人所说,只需定义一个自定义迭代器即可。如果你还想要漂亮的范围迭代,那么你可以定义一个自定义范围 class 返回你的自定义迭代器。
查看下面的工作示例(需要 --std=c++17):
#include <vector>
#include <iostream>
template<typename T>
class SlipIterator {
private:
using iterator = typename std::vector<T>::const_iterator;
iterator i;
iterator slip;
bool has_slipped;
public:
SlipIterator(iterator i, iterator slip): i(i), slip(slip), has_slipped(false) {}
SlipIterator &operator++() {
if ((!has_slipped) && (i == slip))
has_slipped = true;
else
++i;
return *this;
}
bool operator!=(SlipIterator<T> &the_end) const { return i != the_end.i; }
const T &operator*() const { return *i; }
};
template<typename T>
class SlipperyRange {
private:
const std::vector<T> &v;
size_t slip_index;
public:
SlipperyRange(const std::vector<T> &v, size_t slip_index) : v(v), slip_index(slip_index) {}
SlipIterator<T> begin() const { return SlipIterator<T>(v.cbegin(), v.cbegin() + slip_index); }
SlipIterator<T> end() const { return SlipIterator<T>(v.cend(), v.cend()); }
};
int main() {
std::vector<int> v{1,2,3,4,5};
for(const int i: SlipperyRange{v, 2})
std::cout << i << ' ';
std::cout << '\n';
return 0;
}