我有一个虚拟容器“ ISequence”,它用作数组或列表上的容器实现的模板。我已经为数组和列表容器实现了一个迭代器。我想要做的是创建一个虚拟IIterator类,以便我可以创建使用迭代器并接受ISequence的算法作为参数。我的目标是实现自由。
我尝试将虚拟IIterator类添加到没有方法的ISequence中,并且该类继承了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;
然后我由MyIterator在Array中继承。
通过我尝试的操作,我在运行简单的forrange循环时收到“对二进制表达式无效的操作数('ISequence :: IIterator'和'ISequence :: IIterator')”错误消息。
您要实现的概念在C#中非常基础。也许有充分的理由在C ++中不存在任何理由?是的!
您正在尝试使用C ++实现.Net库。 这不是一个好主意,因为该库的设计迎合了C#和CLR(或如今它们称呼它)的限制。 C#在编译时对类型的处理要少得多,并且它没有像C ++那样的编译时通用类型替换系统。通过不使用C ++所提供的功能,您可以重新发明轮子并编写看起来很普通的代码。而且它可能会比所需的速度慢,因为迭代器上的虚拟方法调用易于被频繁调用,其开销显示出来。如果可能的话,编译器将取消某些调用的虚拟化,但这不是要依赖的内容。
概括一下; 默认情况下,除非另外证明,否则直接使用C ++中的.Net生态系统的大多数惯用法都是错误的。]。] 在C ++中,“接口”的概念并不取决于虚拟方法,而是取决于概念,即对类型的约束。在C#中无法实现此目的,在CLR中通常也无法实现,因此设计不支持它。在C ++中,只要所使用的具体类型符合调用者要求的约束(例如,可迭代),编译器就会处理其余的工作。习惯上,您可以使用ranges或迭代器来传递容器,并且接受容器的所有代码都应该是通用的:容器或迭代器的类型应为模板参数,并且不应将迭代器强制为相同的类型-这确实是C ++库旧版本中的库设计错误。
因此,C ++的优点在于您不必定义任何接口。在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 ++中重新实现.Net,它在C ++中看起来不会有太大不同。
#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