Can we inherit from Qt containers?

纵然是瞬间 提交于 2019-12-05 19:02:16

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

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

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

Still, there is an important difference between Qt containers and STL containers: Qt containers have value semantics, and will only perform copy on write, while a std container will copy its full contents when copied. This behavoir accounts for most of Qt base classes, that they will only create a new instance for data, when needed. This implicit sharing of resources is a very important concept to understand when dealing with Qt and its containers.

Your options are as always:

  • composition

    E.g.

     struct MyFancyList
     { 
            QList<MyType> _data;
    
            bool frobnicate() { return true; }
     };
    
  • free functions

    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.

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

Bonus

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

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.

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

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

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 << "\n";
}

Voila. More craziness:

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];

Prints

0.5
0.6
0.7
0.8

DISCLAIMERS

  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.

Look at QStringBuilder for a more real life sample.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!