首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >优雅的对象比较

优雅的对象比较
EN

Stack Overflow用户
提问于 2008-11-16 15:41:42
回答 8查看 1.7K关注 0票数 9

当比较两个(相同类型的)对象时,使用一个compare函数来获取相同类的另一个实例是有意义的。如果我在基类中将其实现为虚函数,则该函数的签名也必须引用派生类中的基类。解决这个问题的优雅方法是什么?这种比较不应该是虚拟的吗?

代码语言:javascript
复制
class A
{
    A();
    ~A();
    virtual int Compare(A Other);
}

class B: A
{
    B();
    ~B();
    int Compare(A Other);
}

class C: A
{
    C();
    ~C();
    int Compare(A Other);
}
EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-05-08 17:43:06

这取决于A、B和C的预期语义以及compare()的语义。比较是一个抽象的概念,它不一定有一个正确的含义(或任何含义,就这一点而言)。这个问题没有唯一的正确答案。

这里有两个场景,其中比较意味着具有相同类层次结构的两个完全不同的东西:

代码语言:javascript
复制
class Object 
{
    virtual int compare(const Object& ) = 0;
    float volume;
};

class Animal : Object 
{
    virtual int compare(const Object& );
    float age;
};

class Zebra  : Animal 
{
    int compare(const Object& );
};

我们可以考虑(至少)两种比较两种斑马的方法:哪一种更老,哪一种体积更大?这两种比较都是有效的,而且很容易计算;不同的是,我们可以使用体积来比较斑马和任何其他物体,但我们只能使用年龄来比较斑马和其他动物。如果我们想要compare()实现年龄比较语义,那么在Object类中定义compare()没有任何意义,因为语义不是在层次结构的这一层定义的。值得注意的是,这些场景都不需要任何强制转换,因为语义是在基类级别定义的(无论是比较体积时是Object,还是比较年龄时是Animal )。

这就引出了一个更重要的问题--有些类并不适合单一的通用compare()函数。通常,实现多个显式声明所比较内容的函数更有意义,比如compare_age()和compare_volume()。这些函数的定义可以发生在继承层次结构中语义变得相关的地方,并且将它们调整为子类应该是微不足道的(如果需要进行调整)。使用compare()或operator==()进行简单的比较通常只对简单的类有意义,因为正确的语义实现是显而易见和明确的。

长话短说。“视情况而定”。

票数 1
EN

Stack Overflow用户

发布于 2008-11-16 17:46:51

我会像这样实现它:

代码语言:javascript
复制
class A{
    int a;

public:
    virtual int Compare(A *other);
};


class B : A{
    int b;

public:
    /*override*/ int Compare(A *other);
};

int A::Compare(A *other){
    if(!other)
        return 1; /* let's just say that non-null > null */

    if(a > other->a)
        return 1;

    if(a < other->a)
        return -1;

    return 0;
}

int B::Compare(A *other){
    int cmp = A::Compare(other);
    if(cmp)
        return cmp;

    B *b_other = dynamic_cast<B*>(other);
    if(!b_other)
        throw "Must be a B object";

    if(b > b_other->b)
        return 1;

    if(b < b_other->b)
        return -1;

    return 0;
}

这非常类似于.NET中的IComparable模式,它工作得非常好。

编辑:

以上需要注意的一点是,a.Compare(b) (其中a是A,b是B)可能会返回相等,并且永远不会抛出异常,而b.Compare(a)会。有时这是你想要的,有时不是。如果不是,那么您可能不希望您的Compare函数是虚拟的,或者您希望比较基本Compare函数中的type_info,如下所示:

代码语言:javascript
复制
int A::Compare(A *other){
    if(!other)
        return 1; /* let's just say that non-null > null */

    if(typeid(this) != typeid(other))
        throw "Must be the same type";

    if(a > other->a)
        return 1;

    if(a < other->a)
        return -1;

    return 0;
}

请注意,派生类的Compare函数不需要更改,因为它们应该调用基类的Compare,在那里将进行type_info比较。但是,您可以将被覆盖的Compare函数中的dynamic_cast替换为static_cast

票数 1
EN

Stack Overflow用户

发布于 2008-11-16 18:11:13

也许,我会这样做:

代码语言:javascript
复制
class A
{
 public:
  virtual int Compare (const A& rhs) const
  {
    // do some comparisons
  }
};

class B
{
 public:
  virtual int Compare (const A& rhs) const
  {
    try
    {
      B& b = dynamic_cast<A&>(rhs)
      if (A::Compare(b) == /* equal */)
      {
        // do some comparisons
      }
      else
        return /* not equal */;
    }
    catch (std::bad_cast&)
    {
      return /* non-equal */
    }
  }
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/294009

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档