我们是否应该能够继承Qt容器,例如QList
,QVector
或QMap
,以便对它们进行专门化并添加功能?如果是这样,我们需要做什么才能确保容器正常工作(虚方法,虚析构函数等等?)。如果没有,为什么不,我有什么其他选择?
答案 0 :(得分:6)
STL和Qt Containers都选择非虚拟析构函数。
有一个有趣的讨论为什么会这样,以及为什么它没有用Qt5修复。
另外,请注意STL样式和Qt容器之间的进一步差异。在他的博客文章An introduction into Qt中引用Jens Weller:
但是,Qt容器和STL容器之间存在重要区别:Qt容器具有值语义,并且仅在写入时执行复制,而std容器在复制时将复制其完整内容。这个行为占据了大多数Qt基类,它们只在需要时才为数据创建一个新实例。在处理Qt及其容器时,这种隐含的资源共享是一个非常重要的概念。
您的选择一如既往:
组合物
E.g。
struct MyFancyList
{
QList<MyType> _data;
bool frobnicate() { return true; }
};
免费功能
E.g。使用非成员操作扩展QList:
template <typename> bool frobnicate(QList<T>& list)
{
// your algorithm
return true;
}
如果您真的想做一些有趣的事情,比如创建隐式转换或重载成员运算符,您可以使用表达式模板。
更新:后者也是QStringBuilder
在新版本中采用的方法。参见
为了好玩,这里有一个(坏的)插图,说明如何使用表达式模板来扩展std::stack<T>
的界面。见Live on Coliru或ideone
众所周知,std::stack
不会为顺序容器建模,因此没有begin()
,end()
或{{1定义。有点hackery,我们可以定义一个eDSL来提供这些功能,而不需要组合或继承。
为了让我们能够以重要方式“重载”被包装类的行为,我们会做到这一点,以便您可以隐式地将operator[]
的结果转换为extend(stack)[n]
,即使堆栈包含例如std::string
。
int
现在我们所要做的就是种子我们的表达模板。我们将使用包装任何#include <string>
#include <stack>
#include <stdexcept>
namespace exprtemplates
{
template <typename T> struct stack_indexer_expr
{
typedef std::stack<T> S;
S& s;
std::size_t n;
stack_indexer_expr(S& s, std::size_t n) : s(s), n(n) {}
operator T() const {
auto i = s.size()-n; // reverse index
for (auto clone = s; !clone.empty(); clone.pop())
if (0 == --i) return clone.top();
throw std::range_error("index out of bounds in stack_indexer_expr");
}
operator std::string() const {
// TODO use `boost::lexical_cast` to allow wider range of T
return std::to_string(this->operator T());
}
};
template <typename T> struct stack_expr
{
typedef std::stack<T> S;
S& s;
stack_expr(S& s) : s(s) {}
stack_indexer_expr<T> operator[](std::size_t n) const {
return { s, n };
}
};
}
:
std::stack
理想情况下,我们的用户从未意识到template <typename T>
exprtemplates::stack_expr<T> extend(std::stack<T>& s) { return { s }; }
命名空间中的确切类型:
exprtemplates
瞧。更疯狂:
#include <iostream>
int main()
{
std::stack<double> s;
s.push(0.5);
s.push(0.6);
s.push(0.7);
s.push(0.8);
std::string demo = extend(s)[3];
std::cout << demo << "\n";
}
打印
auto magic = extend(s);
std::cout << magic[0] << "\n";
std::cout << magic[1] << "\n";
std::cout << magic[2] << "\n";
std::cout << magic[3] << "\n";
double as_double = magic[0];
std::string as_string = magic[0];
<强>免责声明强>
0.5
0.6
0.7
0.8
有一个限制性的界面是有原因的。 查看std::stack
更真实的样本。