比较运算符的虚拟重载

时间:2016-07-11 09:47:01

标签: 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

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

2 个答案:

答案 0 :(得分:2)

我看到的唯一解决方案是不将operator<函数作为虚拟成员函数,而是作为一组重载的非成员函数:One&#34; default&#34;函数,它将A的两个引用作为参数,然后为特殊情况分别进行一次重载。

答案 1 :(得分:2)

///
/// 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
  

精细!但是(我在我的问题中不够精确),当x和y共享相同类型(例如B)时,x&lt; y由特定函数const运算符&lt;给出。 B类中的(B&amp; rhs)const。它不一定是假的。

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

所以这次我们会说任何两个不同的派生类都会有一致的部分排序(即它们永远不会比较相等,而且总是会比另一个更少)但我们会让标准库决定哪一个来第一

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

它会是这样的:

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