我们可以从 Qt 容器继承吗?

Can we inherit from Qt containers?(我们可以从 Qt 容器继承吗?)
本文介绍了我们可以从 Qt 容器继承吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们是否应该能够继承 Qt 容器,例如 QListQVectorQMap 以便专门化它们并添加功能?如果是这样,我们需要做什么才能确保容器正常工作(虚拟方法、虚拟析构函数等?).如果没有,为什么不呢?我还有哪些其他选择?

Are we supposed to be able to inherit from Qt containers such as QList, QVector or QMap in order to specialize them and add functionality? If so, what do we need to do in order to be sure that the container works correctly (virtual methods, virtual destructor etc..?). If not, why not and what other options do I have?

推荐答案

STL 和 Qt 容器都选择非虚拟析构函数.

Both, STL and Qt Containers opt for non virtual destructors.

有一个有趣的讨论为什么会这样,以及为什么它没有被 Qt5 修复.

There is an interesting discussion why this is, and why its not fixed with Qt5.

  • QList 没有虚析构函数,而是继承自 http:///qt-project.org/forums/viewthread/16416

另外,请注意 STL 样式和 Qt 容器之间的进一步差异.在他的博客文章中引用 Jens Weller 对 Qt 的介绍:

Also, note further differences between STL style and Qt containers. Quoting Jens Weller in his Blog post An introduction into Qt:

Qt 容器和 STL 容器之间还有一个重要区别:Qt 容器具有值语义,并且只会在写入时执行复制,而 std 容器在复制时会复制其全部内容.这种行为解释了大多数 Qt 基类,它们只会在需要时为数据创建一个新实例.在处理 Qt 及其容器时,这种隐式的资源共享是一个非常重要的概念.

您的选择一如既往:

  • 作曲

例如

 struct MyFancyList
 { 
        QList<MyType> _data;

        bool frobnicate() { return true; }
 };

  • 免费功能

  • free functions

    例如使用非成员操作扩展 QList:

    E.g. extend QList with non-member operations:

    template <typename> bool frobnicate(QList<T>& list)
    {
         // your algorithm
         return true;
    }
    

  • 如果你真的想做一些古怪的事情,比如创建隐式转换或重载成员运算符,你可以求助于表达式模板.

    If you really wanted to do funcky stuff, like create an implicit conversion or overload a member operator, you could resort to expression templates.

    更新:后者也是QStringBuilder在新版本中采用的方式.见

    Update: the latter is also the approach taken by QStringBuilder in new versions. See

    • 讲座:表达式模板 (视频, 幻灯片) 作者:Volker Krause
    • Lecture: Expression Templates (video, slides) by Volker Krause

    为了好玩,这里有一个(糟糕!)说明如何使用表达式模板来扩展 std::stack<T> 的接口.查看 Live on Coliru 或 ideone

    For fun, here's a (bad!) illustration of how you could use expression templates to extend the interface of std::stack<T>. See it Live on Coliru or ideone

    众所周知,std::stack 没有对 顺序容器 建模,因此没有 begin()end()operator[] 定义.通过一些技巧,我们可以定义一个 eDSL 来提供这些功能,而无需组合或继承.

    As we all know, std::stack doesn't model a sequential container, and therefore doesn't have begin(), end(), or operator[] defined. With a bit of hackery, we can define a eDSL to provide these features, without composition or inheritance.

    为了真正强调您可以以基本方式重载"被包装类的行为,我们将这样做,以便您可以隐式转换 extend(stack)[n] 的结果std::string,即使堆栈包含例如int.

    To really drive the point home that you can 'overload' behaviour of the wrapped class in essential ways, we'll make it so that you can implicitly convert the result of extend(stack)[n] to a std::string, even if the stack contains e.g. 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 };
            }
        };
    }
    

    现在我们要做的就是seed我们的表达式模板.我们将使用一个辅助函数来包装任何 std::stack:

    Now all we have to do is seed our expression templates. We'll use a helper function that wraps any std::stack:

    template <typename T> 
    exprtemplates::stack_expr<T> extend(std::stack<T>& s) { return { s }; }
    

    理想情况下,我们的用户永远不会意识到 exprtemplates 命名空间中的确切类型:

    Ideally, our users never realize the exact types inside exprtemplates namespace:

    #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 << "
    ";
    }
    

    瞧.更疯狂:

    auto magic = extend(s);
    std::cout << magic[0] << "
    ";
    std::cout << magic[1] << "
    ";
    std::cout << magic[2] << "
    ";
    std::cout << magic[3] << "
    ";
    
    double      as_double = magic[0];
    std::string as_string = magic[0];
    

    打印

    0.5
    0.6
    0.7
    0.8
    

    免责声明

    1. 我知道 std::stack 有一个限制性接口是有原因的.
    2. 我知道我的索引实现效率非常高.
    3. 我知道隐式转换是邪恶的.这只是一个人为的例子.
    4. 在现实生活中,使用 Boost::Proto 来运行 DSL.手工完成所有机制存在许多陷阱和陷阱.
    1. I know std::stack has a restrictive interface for a reason.
    2. I know that my indexing implementation has horrific efficiency.
    3. I know that implicit conversions are evil. This is just a contrived example.
    4. In real life, use Boost::Proto to get a DSL going. There are many pitfalls and gotchas in doing all the mechanics by hand.

    查看 QStringBuilder 以获得更真实的示例.

    Look at QStringBuilder for a more real life sample.

    这篇关于我们可以从 Qt 容器继承吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

    本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

    相关文档推荐

    What is the proper function for comparing two C-style strings?(比较两个 C 风格字符串的正确函数是什么?)
    Image Capture with OpenCV - Select Timeout Error(使用 OpenCV 捕获图像 - 选择超时错误)
    SHA256 HMAC using OpenSSL 1.1 not compiling(使用 OpenSSL 1.1 的 SHA256 HMAC 未编译)
    How to make a Debian package depend on multiple versions of libboost(如何制作一个Debian包依赖于多个版本的libboost)
    Why does strcpy_s not exist anywhere on my system?(为什么我系统上的任何地方都不存在 strcpy_s?)
    Simplest way to get current time in current timezone using boost::date_time?(使用 boost::date_time 在当前时区获取当前时间的最简单方法?)