TITLE: virtual operator ==


PROBLEM: "Phil Verghese" <verghese@hpbs2024.boi.hp.com>

I'm trying to implement a virtual operator==, and I'd like to avoid 
having to use RTTI in the derived classes.  


RESPONSE: rmartin@oma.com (Robert C. Martin), 25 Jan 96

If you need to avoid RTTI because your compiler doesn't support it,
then I have no objection.  But if you are avoiding RTTI because you
think it is evil, then I suggest you modify your outlook.  RTTI is not
inherently evil, although the potential for abuse is high.  Still,
implementing operator== with RTTI (i.e. dynamnic_cast) is not one of
those abuses.

If your compiler does not support RTTI, there are some simple ways to
simulate it; which I will explore below.

PV:

   My code looks like this:

   #include <iostream.h>
   class Base
   {
   public:
       Base(int data) : fData(data) {}
       virtual int operator==(const Base& x) const
       {
	   return fData == x.fData;
       }

   protected:
       int fData;
   };

   class Derived : public Base
   {
   public:
       Derived(float data) : fDerData(data), Base(0) {}

       virtual int operator==(const Base& x) const
       {
	   // First, compare base data members
	   int ret=(Base::operator==(x));

	   // Now compare derived data members
	   if (ret==1)
	   {   
	       //------------------------------------ 
	       // Need to do a downcast here, I think
	       //------------------------------------

	       // downcast to Derived, and compare
	       // fDerData members

	       // if downcast fails, return false?

RM:

==========================================================
Right.  With RTTI this looks like the following:

                  Derived* d = dynamic_cast<Derived*>(&x);
                  if (d)
	          {
                    // compare
                  }
                  else
                    ret=0;
=========================================================

PV:
	    }
	   return (ret);
       }

   protected:
       float fDerData;
   };

   Is there any way to implement this while without using RTTI?

RM:

Sure.  You can use the visitor pattern from "Design Patterns", Addison
Wesley, Gamma, et. al.

There is a good example of how to use this pattern in chapter 4 of my
book: Designing Object Oriented C++ Applications using the Booch
Method, Robert Martin, Prentice Hall, 1995 ISBN 0-13-203837-4

class Visitor;

class Base
{
  public:
    virtual void Visit(Visitor&) = 0;
};

class Derived1;
class Derived2;

class Visitor
{
  public:
    virtual void Visit(Derived1*) = 0;
    virtual void Visit(Derived2*) = 0;
};

class Derived1 : public Base;
{
  public:
    virtual void Visit(Visitor& v) {v.Visit(this);}
};

class Derived2 : public Base;
{
  public:
    virtual void Visit(Visitor& v) {v.Visit(this);}
};

class RTTIVisitor : public Visitor
{  
  public:

    RTTIVisitor() : itsD1(0), itsD2(0) {}
    virtual void Visit(Derived1* d1) {itsD1 = d1;}
    virtual void Visit(Derived2* d2) {itsD2 = d2;}

    Derived1* GetD1() {return itsD1;}
    Derived2* GetD2() {return itsD2;}

  private:
    Derived1* itsD1;
    Derived2* itsD2;
};

Derived1* dynamic_cast_Derived1(Base* b)
{
  RTTIVisitor v;
  b.Visit(v);
  return v.GetD1();
}

Derived2* dynamic_cast_Derived2(Base* b)
{
  RTTIVisitor v;
  b.Visit(v);
  return v.GetD2();
}


So, now you can implement your operator== as:

bool Derived1::operator==(const Base& b)
{
  bool ret = true;
  Derived1* d1 = dynamic_cast_Derived1(&b);
  if (d1)
    // compare
  else
    ret = false;
  return ret;
};
