gpt4 book ai didi

c++ - 是否可以创建虚拟迭代器类?

转载 作者:行者123 更新时间:2023-11-28 04:08:24 26 4
gpt4 key购买 nike

我有一个虚拟容器“ISequence”,用作数组或列表上容器实现的模板。我已经为 Array 和 List 容器实现了一个迭代器。我想要做的是创建一个虚拟 IIterator 类,这样我就可以创建使用迭代器并接受 ISequence 作为参数的算法。我的目标是免于实现。

我尝试在没有方法的情况下向 ISequence 添加虚拟 IIterator 类,并且它继承了 std::iterator 但这没有用

ISequence 类:

template <typename T>
class ISequence {
protected:
int length; //length of sequence
public:
virtual int getLength() const = 0; //get length of sequence
virtual bool getIsEmpty() const = 0; //check if empty
public:
virtual T get(int index) const = 0; //get item based on index
virtual T getFirst() const = 0; //get first item
virtual T getLast() const = 0; //get last item
virtual ISequence<T>* getSubSequence(int startIndex, int endIndex) const = 0;
virtual void append(T item) = 0; //add item to the end
virtual void prepend(T item) = 0; //add item to the beginning
virtual void insertAt(int index, T item) = 0; //insert item at a specific point
virtual void remove(T item) = 0; //remove specific item
virtual void replace(int index, T item) = 0; //replace an item
};

带迭代器的数组:

template <typename T>
class ArraySequence: public ISequence<T> {
private:
T* data;
public:
ArraySequence();
ArraySequence(ISequence<T>* sequence);
ArraySequence(int n, int leftLimit, int rightLimit);
ArraySequence<T>& operator=(const ArraySequence<T>& sequence);
~ArraySequence();
public:
virtual int getLength() const override;
virtual bool getIsEmpty() const override;
public:
virtual T get(int index) const override;
virtual T getFirst() const override;
virtual T getLast() const override;
virtual ArraySequence<T>* getSubSequence(int startIndex, int endIndex) const override;
virtual void append(T item) override;
virtual void prepend(T item) override;
virtual void insertAt(int index, T item) override;
virtual void remove(T item) override;
virtual void replace(int index, T item) override;
private:
class MyIterator: public std::iterator<std::random_access_iterator_tag, T> {
friend class ArraySequence;
private:
T* pos;
MyIterator(T* pos);
public:
MyIterator(const MyIterator &it);
~MyIterator();
public:
typename MyIterator::reference operator*() const;
typename MyIterator::pointer operator->() const;
typename MyIterator::reference operator[](const typename MyIterator::difference_type& n) const;
typename MyIterator::difference_type operator-(const MyIterator& it) const;
MyIterator operator++(int);
MyIterator& operator++();
MyIterator operator--(int);
MyIterator& operator--();
MyIterator operator+(const typename MyIterator::difference_type& n) const;
MyIterator& operator+=(const typename MyIterator::difference_type& n);
MyIterator operator-(const typename MyIterator::difference_type& n) const;
MyIterator& operator-=(const typename MyIterator::difference_type& n);
bool operator!=(const MyIterator& it) const;
bool operator==(const MyIterator& it) const;
bool operator<(const MyIterator& it) const;
bool operator>(const MyIterator& it) const;
bool operator<=(const MyIterator& it) const;
bool operator>=(const MyIterator& it) const;
};
public:
typedef MyIterator iterator;
typedef MyIterator const const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};

我的抽象 IIterator 代码(作为 ISequence 的补充):

protected:
class IIterator: public std::iterator<std::random_access_iterator_tag, T> { //virtual Iterator class
};
public:
typedef IIterator iterator;
typedef IIterator const const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;

然后我通过Array中的MyIterator继承

通过我的尝试,当我运行简单的 forrange 循环时,我得到了“二进制表达式的无效操作数(‘ISequence::IIterator’和‘ISequence::IIterator’)”错误消息。

最佳答案

您要实现的概念在 C# 中相当基础。也许 C++ 中不存在这些是有充分理由的?是的!

您正在尝试使用 C++ 实现 .Net 库。 这不是一个好主意,因为该库的设计迎合了 C# 和 CLR(或他们现在所说的任何东西)的局限性。 C# 在编译时对类型的处理要少得多,而且它没有像 C++ 那样的编译时泛型类型替换系统。通过不使用 C++ 提供的功能,您正在重新发明轮子并编写看起来非常单一的代码。而且它可能会比需要的慢,因为迭代器上的虚拟方法调用很容易被经常调用,它们的开销显示出来。如果可以的话,编译器会去虚拟化一些调用,但这不是可以依赖的东西。

概括一点; 默认情况下,在 C++ 中直接使用 .Net 生态系统中的大多数习语都是错误的,除非另有证明

在 C++ 中,“接口(interface)”的概念不依赖于虚拟方法,而是依赖于概念——即类型约束。在 C# 中没有办法实现这一点,通常在 CLR 中也没有,设计不支持它。在 C++ 中,只要使用的具体类型符合调用者要求的约束(例如可迭代),编译器就会处理其余的事情。习惯上,您可以使用 ranges 传递容器或迭代器,所有接受这些的代码都应该是通用的:容器或迭代器的类型应该是一个模板参数,并且迭代器不应该被强制为相同的类型——这在旧版本中确实是一个库设计错误C++ 库。

因此,C++ 的美妙之处在于您不必定义任何接口(interface)。在 C++20 中,您可以使用概念来约束类型,但除此之外,它很简单——比在 C# 中简单得多。范围的想法是让对象的行为“像”容器,即您可以使用 range-for 对它们进行迭代,但它们不一定是容器——它们可能只是在容器上表达一系列元素的一种方式,甚至动态生成。

如果您正在考虑这样做以支持将代码从 C# 移植到 C++,那么只需忘记对 ISequence 等的需求。只需使用泛型类型参数,如果需要,可以选择使用概念约束它们您正在使用 C++20 编译器,并且您已准备就绪。就这么简单。容器可以是任何东西。即使是普通的“C”数组(不寒而栗 - 不要使用它们,请始终使用 std::array!)。

假设我们有以下 C# 代码:

System.IO.TextWriter cout = Console.Out;

Action<System.Collections.IEnumerable> printValues = (values) =>
{
cout.WriteLine("printValues");
foreach (var v in values)
cout.Write($"{v} ");
cout.Write("\n");
};

var list_of_ints = new List<int>{1, 2, 3, 4, 5};
var vector_of_strings = new String[]{"a", "b", "c", "d"};
cout.WriteLine("* Entire containers");
printValues(list_of_ints);
printValues(vector_of_strings);
cout.WriteLine("\n* Subranges of containers");
printValues(list_of_ints.GetRange(1, list_of_ints.Count() - 1));
printValues(vector_of_strings.Take(vector_of_strings.Count() - 1));

输出:

* Entire containers
printValues
1 2 3 4 5
printValues
a b c d

* Subranges of containers
printValues
2 3 4 5
printValues
a b c

它在 C++ 中看起来并没有太大不同,只要您坚持使用 C++ 的惯用语并且不要尝试在 C++ 中重新实现 .Net:

#include <forward_list>
#include <iostream>
#include <string>
#include <vector>

// This will accept entire containers, as well as C++20 ranges.
template <class C> void printValues(const C &values) {
std::cout << __FUNCTION__ << " with container\n";
for (auto &v : values)
std::cout << v << " ";
std::cout << "\n";
}

// This is the more legacy way of doing it - to stay compatible with C++98 (shiver).
template <class I1, class I2> void printValues(I1 start, I2 end) {
std::cout << __FUNCTION__ << " with iterators\n";
for (; start != end; ++start)
std::cout << *start << " ";
std::cout << "\n";
}

int main() {
std::forward_list<int> list_of_ints{1,2,3,4,5};
std::vector<std::string> vector_of_strings{"a", "b", "c", "d"};

std::cout << "* Entire containers\n";
printValues(list_of_ints);
printValues(vector_of_strings);
std::cout << "\n* Subranges of containers\n";
printValues(std::next(list_of_ints.cbegin()), list_of_ints.cend());
printValues(vector_of_strings.cbegin(), std::prev(vector_of_strings.cend()));
}

输出:

* Entire containers
printValues with container
1 2 3 4 5
printValues with container
a b c d

* Subranges of containers
printValues with iterators
2 3 4 5
printValues with iterators
a b c

关于c++ - 是否可以创建虚拟迭代器类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58304719/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com