Можно ли избавиться от 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 в реализации операторов< ?
Необходимость в каждом классе знать обо всех остальных, которые подходят для сравнения, очень утомляет, усложняет и загромождает код.
Re: Можно ли избавиться от dynamic_cast ?
От: LaptevVV Россия  
Дата: 03.08.13 13:16
Оценка:
Здравствуйте, Аноним, Вы писали:

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

...
А>Вопрос в том, можно ли избавиться от dynamic_cast в реализации операторов< ?
А>Необходимость в каждом классе знать обо всех остальных, которые подходят для сравнения, очень утомляет, усложняет и загромождает код.
Ну что ж вы классику-то не читаете!
1. В книге Банды 4-х есть паттерн Интерпретатор — объектно-ориентированный.
2. Мультиметоды спасут отца русской демократии? В книге Банды 4-х — паттерн Визитор. У Мейерса в книгах — хорошо написано.
Да хоть бы и в моей книжке тоже... :)
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Можно ли избавиться от dynamic_cast ?
От: Nikе Россия  
Дата: 03.08.13 13:39
Оценка:
Здравствуйте, Аноним, Вы писали:

Жуткий код. Как верно заметил Лаптев — табличку функций сравнения вам нужно. По обеим осям — тип значения, в узле — функция сравнения. Дальше — больше, можно делать пирамидки или более сложные иерархии.
Табличка может быть динамической, через вектор. Может статической, через визитор.
Нужно разобрать угил.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.