Можно ли избавиться от dynamic_cast ?
От: Аноним  
Дата: 03.08.13 13:11
Оценка:
Пишу простейший микро-компилятор, способный вычислять логические выражения. Понимаемый компилятором синтаксис (предварительно): операторы БОЛЬШЕ, МЕНЬШЕ, РАВНО, НЕ, И, ИЛИ и микро-язык запросов, берущий значения переменных из динамически создаваемой во время выполнения структуры. Навскидку набросал за полдня драфт:

class IConditionItem
{
public:
    virtual ~IConditionItem()
    {
    }

    virtual bool Evaluate() = 0;
    virtual void Insert( IConditionItem * ) = 0;
};

class ICalculable  : public IConditionItem
{
public:
    virtual ~ICalculable()
    {
    }

    virtual bool operator<( ICalculable const * _right ) = 0;
    
    bool operator>( IConditionItem const * _right )
    {
        return( _right < this );
    }

    bool operator==( IConditionItem const * _right )
    {
        return( !(( this < _right ) && ( _right < this )) );
    }

    void Insert( IConditionItem * pConditionItem )
    {
        throw "UNIMPLEMENTED!";
    }
};

class Equals : public IConditionItem
{
    vector< ICalculable * > m_vArgList;

public:
    Equals()
    {
    }

    virtual bool Evaluate()
    {
        m_vArgList[ 0 ]->Evaluate();
        m_vArgList[ 1 ]->Evaluate();
        
        return( m_vArgList[0] == m_vArgList[1] );
    }

    void Insert( IConditionItem * pConditionItem )
    {
        ICalculable * pCalculable = dynamic_cast< ICalculable* >( pConditionItem );
        
        if( pCalculable )
        {
            m_vArgList[ m_vArgList.size() ] = pCalculable;
        }
    }
};

class Less : public IConditionItem
{
    vector< ICalculable * > m_vArgList;

public:
    Less()
    {
    }

    virtual bool Evaluate()
    {
        assert( m_vArgList.size() == 2 );

        m_vArgList[ 0 ]->Evaluate();
        m_vArgList[ 1 ]->Evaluate();
        
        return( m_vArgList[0]->operator<( m_vArgList[1] ));
    }

    void Insert( IConditionItem * pConditionItem )
    {
        ICalculable * pCalculable = dynamic_cast< ICalculable* >( pConditionItem );
        
        if( pCalculable )
        {
            m_vArgList.push_back( pCalculable );
        }
        else
        {
            // warning()
            fprintf( stderr, 
                "Inappropriate argument type! (%s)\n", 
                typeid( pConditionItem ).name() 
                );
        }
    }
};

class DecimalValue;
class IntegerValue : public ICalculable
{
private:
    int m_nValue;

private:
    bool Evaluate()
    {
        // TODO: get the real value at runtime
        return( !!m_nValue );
    };

public:
    IntegerValue() : m_nValue( 0 )
    {
    }

    double Raw() const
    {
        return( m_nValue );
    }

    void Set( int nValue )
    {
        m_nValue = nValue;
    }

    virtual bool operator<( ICalculable const * _right );
};

class DecimalValue : public ICalculable
{
private:
    double m_dblValue;

private:
    bool Evaluate()
    {
        // TODO: get the real value at runtime
        return( !!m_dblValue );
    };

public:
    DecimalValue() : m_dblValue( 0 )
    {
    }

    double Raw() const
    {
        return( m_dblValue );
    }

    void Set( double dblValue )
    {
        m_dblValue = dblValue;
    }

    bool operator<( ICalculable const * _right )
    {
        DecimalValue const * pDecimal = dynamic_cast< DecimalValue const * >( _right );
        IntegerValue const * pInteger = dynamic_cast< IntegerValue const * >( _right );

        if( pDecimal )
        {
            return( Raw() < pDecimal->Raw() );
        }
        else
        if( pInteger )
        {
            return( Raw() < pInteger->Raw() );
        }
        
        throw "UNIMPLEMENTED!";
        return( false );
    };
};

bool IntegerValue::operator<( ICalculable const * _right )
{
    DecimalValue const * pDecimal = dynamic_cast< DecimalValue const * >( _right );
    IntegerValue const * pInteger = dynamic_cast< IntegerValue const * >( _right );

    if( pDecimal )
    {
        return( Raw() < pDecimal->Raw() );
    }
    else
    if( pInteger )
    {
        return( Raw() < ( double )pInteger->Raw() );
    }
        
    throw "UNIMPLEMENTED!";
    return( false );
}

class Condition
{
private:
    IConditionItem * m_pConditionItem;
    Condition( Condition const & );

public:
    Condition( IConditionItem * pConditionItem ) :
        m_pConditionItem( pConditionItem )
    {
    }
    
    bool Evaluate()
    {
        return( m_pConditionItem->Evaluate() );
    }
};


int main( int argc, char* argv[] )
{
    Less myLess;

    DecimalValue dblVal;
    IntegerValue intVal;
    
    dblVal.Set( 12.24 );
    intVal.Set( 12 );

    myLess.Insert( &dblVal );
    myLess.Insert( &intVal );

    Condition cond( &myLess );

    bool b = cond.Evaluate();
    return( 0 );
}


Вопрос в том, можно ли избавиться от dynamic_cast в реализации операторов< ?
Необходимость в каждом классе знать обо всех остальных, которые подходят для сравнения, очень утомляет, усложняет и загромождает код.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.