c++ - 比较运算符的虚拟重载

标签 c++

假设我们有以下片段:

class A
{
public:
    virtual bool operator< (const A &rhs) const;
};

class B: public A;

class C: public A;

我希望比较取决于左侧和右侧的真实类型,例如:

x < y == true    if type(x) == B and type(y) == C
x < y == false   if type(x) == C and type(y) == B

情况可能更复杂,派生类比两个多得多。当然,operator<必须是虚函数。有没有一种优雅的方式来写这个?

最佳答案

///
/// goal:       provide partial ordering of objects derived from A on the basis
///             only of class type.
/// constraint: ordering specified by us
///

#include <vector>
#include <typeindex>
#include <algorithm>
#include <iostream>


class A
{
public:
    virtual bool operator< (const A &rhs) const = 0;

    static const std::vector<std::type_index>& ordering();
};

template<class T> struct impl_A : public A
{
    bool operator< (const A &rhs) const override
    {
        auto& o = ordering();
        auto first = std::begin(o);
        auto last = std::end(o);

        auto il = std::find(first, last, typeid(T));
        auto ir = std::find(first, last, typeid(rhs));
        return il < ir;
    }
};

class B: public impl_A<B> {};

class C: public impl_A<C> {};

const std::vector<std::type_index>& A::ordering()
{
    // specify fording of types explicitly
    static const std::vector<std::type_index> _ordering { typeid(B), typeid(C) };
    return _ordering;
}



void test(const A& l, const A& r)
{
    if (l < r) {
        std::cout << typeid(l).name() << " is less than " << typeid(r).name() << std::endl;
    }
    else {
        std::cout << typeid(l).name() << " is not less than " << typeid(r).name() << std::endl;
    }
}

int main()
{
    test(B(), C());
    test(B(), B());
    test(C(), B());
    test(C(), C());

}

示例输出(clang):

1B is less than 1C
1B is not less than 1B
1C is not less than 1B
1C is not less than 1C

Fine! But (I was not precise enough in my question), when x and y share the same type (for example B), the result of x < y is given by a specific function const operator< (B &rhs) const in class ̀B. It is not necessarily false`.

好的,我们正在修改要求。这是用户(他们很少意识到规范中所要求的详细程度)和开发人员(意识到了!)之间的正常对话。

所以这次我们会说任何两个不同的派生类都将具有一致的偏序(即它们永远不会比较相等,一个总是比另一个少)但是我们将让标准库决定哪个派生类出现首先。

但是,当被比较的两个类属于同一类型时,我们希望实际比较它们的值以确定顺序(和等价性)。

它会是这样的:

#include <vector>
#include <typeinfo>
#include <algorithm>
#include <iostream>
#include <tuple>
#include <iomanip>


class A
{
public:
    virtual bool operator< (const A &rhs) const = 0;

    std::ostream& print(std::ostream& os) const {
        handle_print(os);
        return os;
    }

private:
    virtual void handle_print(std::ostream&) const = 0;
};

std::ostream& operator<<(std::ostream& os, const A& a) {
    return a.print(os);
}

template<class T> struct impl_A : public A
{
    bool operator< (const A &rhs) const override
    {
        auto& rhs_info = typeid(rhs);
        auto& lhs_info = typeid(T);
        if (rhs_info == lhs_info) {
            // same type, so do comparison
            return static_cast<const T&>(*this).ordering_tuple() < static_cast<const T&>(rhs).ordering_tuple();
        }
        else {
            return lhs_info.before(rhs_info);
        }
    }
};

class B: public impl_A<B> {
public:
    B(int v) : _value(v) {}

    auto ordering_tuple() const {
        return std::tie(_value);
    }

private:

    void handle_print(std::ostream& os) const override {
        os << _value;
    }

    int _value;
};



class C: public impl_A<C> {
public:
    C(std::string v) : _value(std::move(v)) {}

    auto ordering_tuple() const {
        return std::tie(_value);
    }

private:

    void handle_print(std::ostream& os) const override {
        os << std::quoted(_value);
    }

    std::string _value;
};

// now we need to write some compare functions


void test(const A& l, const A& r)
{
    if (l < r) {
        std::cout << l << " is less than " << r << std::endl;
    }
    else {
        std::cout << l << " is not less than " << r << std::endl;
    }
}

int main()
{
    test(B(1), C("hello"));
    test(B(0), B(1));
    test(B(1), B(0));
    test(B(0), B(0));
    test(C("hello"), B(1));
    test(C("goodbye"), C("hello"));
    test(C("goodbye"), C("goodbye"));
    test(C("hello"), C("goodbye"));

}

示例结果:

1 is less than "hello"
0 is less than 1
1 is not less than 0
0 is not less than 0
"hello" is not less than 1
"goodbye" is less than "hello"
"goodbye" is not less than "goodbye"
"hello" is not less than "goodbye"

关于c++ - 比较运算符的虚拟重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38303843/

相关文章:

C++ 深度优先搜索带前缀参数的 Trie

c++ - 检查 Windows 7 上是否有另一个进程可识别 DPI

c++ - C语言中如何使用内存地址?它们是十六进制还是无符号整数?

c++ - GL 数学 : GLM rotate function rotates the entire coordinate system

c++ - 获取屏幕的屏幕宽度和高度

c++ - 在 Qt Creator 中将串行数据从 QSerialPort 提取到 double 的正确语法是什么?

c++ - 检查是否使用 MATLAB mex 编译

c++ - 使用多态性将派生类的值复制到基类

c++ - 内联类函数和共享库 (dll) 构建

c++ - std::call_once,应该什么时候用?