如何在没有 dynamic_cast 的情况下在派生类型上实现“less”?

问题描述 投票:0回答:3

我想对以下类实现“less”类型的操作:

class Base {
  public:
    virtual int type() const = 0;
  private:
    int b;
};

class Derived1 : public Base{
  public:
    virtual int type() const { return 1; }
  private:
    int d1; 
};

class Derived2 : public Base{
  public:
    virtual int type() const { return 2; }
  private:
    int d2;
};

where

o1 < o2
如果它的类型更小,如果类型相等则比较元素(首先是 b 然后是 d1 或 d2)。

请注意,还有其他具有类似问题结构的操作(例如等于)。

如何在不使用

dynamic_cast
的情况下做到这一点?

c++ class inheritance operator-overloading virtual
3个回答
1
投票

你不需要

dynamic_cast
也不需要
type
。就此而言,也根本没有公共成员。

class Base {
  virtual bool less( Base const & rhs ) const {
    return false;
  }

  int b;

  friend bool operator < ( Base const & lhs, Base const & rhs ) {
    std::type_info const & ltype = typeid (lhs);
    std::type_info const & rtype = typeid (rhs);
    if ( ltype == rtype ) {
      if ( lhs.b < rhs.b ) return true;
      if ( rhs.b < lhs.b ) return false;
      return lhs.less( rhs ); // Dynamic types of lhs and rhs already match.
    }
    return ltype.before( rtype );
  }
};

class Derived1 : public Base{
  virtual bool less( Base const & rhs_base ) const {
    // Since rhs_base is known to be of this type, use static_cast.
    Derived1 const & rhs = static_cast< Derived1 const & >( rhs_base );
    return d1 < rhs.d1;
  }

  int d1; 
};

// Same for Derived2

http://coliru.stacked-crooked.com/a/af1aae28630878f5(包括测试)


1
投票

经营者可以看下面的方式

class Base {
 public:
  virtual int type() const = 0;
  virtual int get_value() const { return b; }
 private:
  int b;
};

class Derived1 : public Base{
 public:
  virtual int type() const { return 1; }
  virtual int get_value() const { return d1; }     
 private:
  int d1; 
};

class Derived2 : public Base{
 public:
  virtual int type() const { return 2; }
  virtual int get_value() const { return d2; }     
 private:
  int d2;
};

bool operator <( const Base &lhs, const Base &rhs )
{
    int t1 = lhs.type();
    int t2 = rhs.type();
    int b1 = lhs.Base::get_value();
    int b2 = rhs.Base::get_value();
    int d1 = lhs.get_value();
    int d2 = rhs.get_value();

    return std::tie( t1, b1, d1 ) < std::tie( t2, b2, d2 );  
}

这是一个演示程序。我又添加了一个派生类,以表明运算符不依赖于派生类的数量。

#include <iostream>
#include <iomanip>
#include <tuple>

class Base 
{
public:
    Base( int x ) : b( x ) {}        
    virtual int type() const = 0;
    virtual int get_value() const { return b; }

private:
    int b;
};

class Derived1 : public Base
{
public:
    Derived1( int x, int y ) : Base( y ), d1( x ) {}
    virtual int type() const { return 1; }
    virtual int get_value() const { return d1; }     

private:
    int d1; 
};

class Derived2 : public Base
{
public:
    Derived2( int x, int y ) : Base( y ), d2( x ) {}
    virtual int type() const { return 2; }
    virtual int get_value() const { return d2; }     

private:
    int d2;
};

class Derived3 : public Base
{
public:
    Derived3( int x, int y ) : Base( y ), d3( x ) {}
    virtual int type() const { return 2; }
    virtual int get_value() const { return d3; }     

private:
    int d3;
};

bool operator <( const Base &lhs, const Base &rhs )
{
    int t1 = lhs.type();
    int t2 = rhs.type();
    int b1 = lhs.Base::get_value();
    int b2 = rhs.Base::get_value();
    int d1 = lhs.get_value();
    int d2 = rhs.get_value();

    return std::tie( t1, b1, d1 ) < std::tie( t2, b2, d2 );  
}

int main()
{
    Derived1 d11( 1, 2 );
    Derived1 d12( 1, 1 );
    
    std::cout << "d11 < d12 = " << std::boolalpha <<( d11 < d12 ) << std::endl;
    std::cout << "d12 < d11 = " << std::boolalpha <<( d12 < d11 ) << std::endl;
    
    Derived2 d21( 1, 2 );
    
    std::cout << "d21 < d11 = " << std::boolalpha <<( d21 < d11 ) << std::endl;
    std::cout << "d11 < d21 = " << std::boolalpha <<( d11 < d21 ) << std::endl;

    Derived3 d31( 1, 2 );

    std::cout << "d31 < d21 = " << std::boolalpha <<( d31 < d21 ) << std::endl;
    std::cout << "d21 < d31 = " << std::boolalpha <<( d21 < d31 ) << std::endl;
}    

程序输出为

d11 < d12 = false
d12 < d11 = true
d21 < d11 = false
d11 < d21 = true
d31 < d21 = false
d21 < d31 = false

0
投票

你需要双重派遣:

class Base
{
public:
    virtual int type() const = 0;
    virtual bool greaterWithBase(const Base&) const = 0;
    virtual bool lessWithDerived1(const Derived1&) const = 0;
    virtual bool lessWithDerived2(const Derived2&) const = 0;
private:
    int b;
};

class Derived1 : public Base
{
public:
    int type() const override { return 1; }
    bool greaterWithBase(const Base& base) const override
    {
        return base.lessWithDerived1(*this);
    }

    bool lessWithDerived1(const Derived1& rhs) const override
    {
        return std::tie(b, d1) < std::tie(rhs.b, rhs.d1);
    }
    bool lessWithDerived2(const Derived2&) const override {return true;}
private:
    int d1;
};

class Derived2 : public Base
{
public:
    int type() const override { return 1; }
    bool greaterWithBase(const Base& base) const override
    {
        return base.lessWithDerived2(*this);
    }

    bool lessWithDerived1(const Derived1&) const override {return false;}
    bool lessWithDerived2(const Derived2& rhs) const override
    {
        return std::tie(b, d2) < std::tie(rhs.b, rhs.d2);
    }
private:
    int d2;
};
© www.soinside.com 2019 - 2024. All rights reserved.