David said:
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;
}