- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个虚拟容器“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/
有WHERE 1=1有什么作用如果您在脚本(伪代码)中编写此请求: sql = "SELECT f1,f2,f3 FROM t WHERE 1=1" ++ restOfTheClause
这个问题已经有答案了: R: Convert delimited string into variables (3 个回答) 已关闭 5 年前。 我有一个包含电影数据的表,在最后一列中,它包含电影所属
假设我有一个基类: struct A{ virtual void foo() = 0; }; 然后假设我有一个这样的派生类: struct B : public virtual A{ voi
我有一个小问题,我的 << 运算符没有被正确调用。 这是我的: class SomeInterface { friend std::ostream& operator<<(std::ostrea
首先,我来自 Java 社区,并且仍然是 C++ 的学习者。 请看下面的类 第二张图片显示了类“GameObject”的子类。它还有一个 Display() 方法。 GameObject类有5个子类,
我这里遇到了一些问题。我试图让我的代码像 java 中的接口(interface)一样工作。这个类被其他 2 个继承,因为它们导致了一些问题。而且我还想知道我是否做对了,以及改进我的代码的方法。我是新
在 C++ 中,我有一个基类 A,一个子类 B。两者都有虚方法 Visit。我想在 B 中重新定义“访问”,但 B 需要访问每个 A(以及所有子类)的“访问”功能。 我有类似的东西,但它告诉我 B 无
我有一个抽象类,它是类层次结构的根。该根类有一个带有一些简单实现的方法,似乎没有必要随时随地更改该实现。 使该方法成为非虚方法很好,但是某些子类可能会意外地重新实现它。在这种情况下,虚拟 final方
在 MSDN 上,我发现在抽象方法声明中使用“virtual”修饰符是错误的。我的一位同事应该是非常有经验的开发人员,但他在他的代码中使用了这个: public abstract class Busi
C++ 虚函数表是仅用于确定调用虚函数时应该执行哪一段代码,还是在运行时有其他用途? 在维基百科上,它列出了“动态调度”作为一个原因,但没有深入了解 C++ 的更多细节...... 最佳答案 一些实现
页面大小是否恒定?更具体地说,getconf PAGE_SIZE 给出 4096,这很公平。但这可以通过程序的运行时间改变吗?或者它在整个操作系统进程生成过程中是否保持不变。 IE。 , 进程是否可能
析构函数(当然还有构造函数)和其他成员函数之间的区别在于,如果常规成员函数在派生类中具有主体,则仅执行派生类中的版本。而在析构函数的情况下,派生版本和基类版本都会被执行? 很高兴知道在析构函数(可能是
如果一个函数被定义为虚函数并且与纯虚函数相同,这究竟意味着什么? 最佳答案 来自 Wikipedia's Virtual function... In object-oriented programm
我有一个在 Jetty 下运行的应用程序,我希望该应用程序返回自引用绝对 URL(生成 RSS 提要时,因此客户端必须能够在没有“当前 URL”上下文的情况下工作)。 问题是我事先不知道应用程序将部署
如何在两个virtualtreeview之间复制以复制所有列,而不仅仅是第一列? 复制前: 复制后: 最佳答案 树控件不保存任何数据。它不包含要显示的列数据,因此无法复制它。而是,当树控件想要显示任何
我已将 ShowHint 设置为 true 并将 HintMode 设置为 hmToolTip,但是当我将光标悬停在控件上时,我的 OnGetHint() 事件处理程序甚至没有断点。 知道我做错了什么
我的 friend 正在 Delphi 中使用 VirtualTreeView 工作,并且遇到了下一个问题:他有两列,第一列的每一行都有数据和子项。是否可以不更改第一列宽度来设置最大子列宽度? 图例:
我在我的 Virtual TreeView Component 中使用 TVirtualStringTree ( Delphi project 的一部分)我想创建一个 View ,其中 2 列可以有可
我想遍历 VirtualTreeView 的所有根并将其删除。 我不想清除它。 我收到此代码的访问冲突: var Node : PVirtualNode; begin if VirtualStri
我有一个可以输出表单的 PHP 文件。我想在服务器端调用这个 PHP 文件(当前使用“include”),填写并提交。 这样更好,因此我不必干预实际的 PHP 表单,只需处理表示层,以便数据可以被它自
我是一名优秀的程序员,十分优秀!