David Sobey wrote:

OK Here's the long and short of it. Num will soon be joined by vector,

matrix, complex etc. It spits out an error

when i try to evaluate the expression, it can't convert a Node pointer to a

Num pointer. I can't cast them, because

when i eventually have at least 5 different child classes of Node, it will

become a nightmare of code to cast for each type.

Any ideas appreciated.

You need virtual functions.

In particular the problem you are heading into is know

under the name 'double dispatch'. You need a virtual

function which is selected based on 2 base pointers and

that is something that is not pretty in C++ (C++ does not

directly support that).

Also: You need to decide what should happen if you try to

add a Number with a Matrix. Is that a valid operation? If

yes, how should it be performed? Same with Vector and Matrix

or Vector and Number, all combinations of each with each.

The following implements this for int numbers and double numbers

(Error checking is ommitted for brevity)

It is not pretty, but study it to figure out how this works.

Here is the code (You have been warned)

#include <iostream>

#include <map>

#include <string>

using namespace std;

enum Operations { ADD, SUBTRACT };

class Node;

typedef Node* (*Fnct)( Node* pLeft, Node* pRight );

typedef map< string, Fnct > HandlerMap;

class Dispatcher

{

public:

Node* Evaluate( Node* pLeft, Node* ppRight );

void AddHandler( const type_info& What, const type_info& With, Fnct Handler );

protected:

HandlerMap m_Functions;

};

Dispatcher AddDispatcher;

Dispatcher SubDispatcher;

class Node

{

public:

virtual Node* Evaluate() = 0;

virtual void Output() { cout << "An unknown node\n"; }

};

class IntNumber: public Node

{

public:

IntNumber( int Val )

: m_Value( Val )

{}

Node* Evaluate() { return new IntNumber( *this ); }

void Output() { cout << "An Int: " << m_Value << "\n"; }

int GetValue() { return m_Value; }

protected:

int m_Value;

};

class DoubleNumber: public Node

{

public:

DoubleNumber( double Val )

: m_Value( Val )

{}

Node* Evaluate() { return new DoubleNumber( *this ); }

void Output() { cout << "A Double: " << m_Value << "\n"; }

int GetValue() { return m_Value; }

protected:

double m_Value;

};

class Branch : public Node

{

public:

Branch( Operations Op, Node* pLeft, Node* pRight )

: m_Operation( Op ), m_pLeft( pLeft ), m_pRight( pRight )

{}

Node* Evaluate();

protected:

Node* m_pLeft;

Node* m_pRight;

Operations m_Operation;

};

Node* Branch::Evaluate()

{

Node* pLeftResult = m_pLeft->Evaluate();

Node* pRightResult = m_pRight->Evaluate();

Node* pResult = 0;

if( m_Operation == ADD )

pResult = AddDispatcher.Evaluate( pLeftResult, pRightResult );

else if( m_Operation == SUBTRACT )

pResult = SubDispatcher.Evaluate( pLeftResult, pRightResult );

delete pLeftResult;

delete pRightResult;

return pResult;

}

void Dispatcher::AddHandler( const type_info& What, const type_info& With, Fnct Handler )

{

string Key = What.name();

Key += With.name();

m_Functions[Key] = Handler;

}

Node* Dispatcher::Evaluate( Node* pLeft, Node* pRight )

{

string Key = typeid( *pLeft ).name();

Key += typeid( *pRight ).name();

if( m_Functions.find( Key ) != m_Functions.end() ) {

return (*m_Functions[Key])( pLeft, pRight );

}

cout << "There is no handler for "

<< typeid( *pLeft ).name()

<< " - "

<< typeid( *pRight ).name()

<< endl;

return 0;

}

Node* AddIntInt( Node* pLeft, Node* pRight )

{

IntNumber* pL = dynamic_cast< IntNumber* >(pLeft);

IntNumber* pR = dynamic_cast< IntNumber* >(pRight);

IntNumber* pResult = new IntNumber( pL->GetValue() + pR->GetValue() );

cout << "Adding int + int (->int): "

<< pL->GetValue()

<< " + "

<< pR->GetValue()

<< " -> "

<< pResult->GetValue()

<< endl;

return pResult;

}

Node* AddIntDouble( Node* pLeft, Node* pRight )

{

IntNumber* pL = dynamic_cast< IntNumber* >(pLeft);

DoubleNumber* pR = dynamic_cast< DoubleNumber* >(pRight);

DoubleNumber* pResult = new DoubleNumber( pL->GetValue() + pR->GetValue() );

cout << "Adding int + double (->double): "

<< pL->GetValue()

<< " + "

<< pR->GetValue()

<< " -> "

<< pResult->GetValue()

<< endl;

return pResult;

}

Node* AddDoubleInt( Node* pLeft, Node* pRight )

{

DoubleNumber* pL = dynamic_cast< DoubleNumber* >(pLeft);

IntNumber* pR = dynamic_cast< IntNumber* >(pRight);

DoubleNumber* pResult = new DoubleNumber( pL->GetValue() + pR->GetValue() );

cout << "Adding double + int (->double): "

<< pL->GetValue()

<< " + "

<< pR->GetValue()

<< " -> "

<< pResult->GetValue()

<< endl;

return pResult;

}

Node* SubIntInt( Node* pLeft, Node* pRight )

{

IntNumber* pL = dynamic_cast< IntNumber* >(pLeft);

IntNumber* pR = dynamic_cast< IntNumber* >(pRight);

IntNumber* pResult = new IntNumber( pL->GetValue() - pR->GetValue() );

cout << "Subtracting int - int (->double): "

<< pL->GetValue()

<< " + "

<< pR->GetValue()

<< " -> "

<< pResult->GetValue()

<< endl;

return pResult;

}

int main()

{

AddDispatcher.AddHandler( typeid( IntNumber ), typeid( IntNumber ), AddIntInt );

AddDispatcher.AddHandler( typeid( IntNumber ), typeid( DoubleNumber ), AddIntDouble );

AddDispatcher.AddHandler( typeid( DoubleNumber ), typeid( IntNumber ), AddDoubleInt );

SubDispatcher.AddHandler( typeid( IntNumber ), typeid( IntNumber ), SubIntInt );

IntNumber Num1( 5 );

IntNumber Num2( 7 );

DoubleNumber Num3( 3.0 );

Branch SubExp1( SUBTRACT, &Num1, &Num2 );

Branch Top( ADD, &Num3, &SubExp1 );

Node* pResult = Top.Evaluate();

pResult->Output();

delete pResult;

return 0;

}

--

Karl Heinz Buchegger

kb******@gascad.at