Re: Downcasting base-class objects to a derived-class
 
In article 
<a16c084f-3adc-4fd8-9577-521ffafcceb6@f3g2000yqf.googlegroups.com>,
 vsk <vminch@gmail.com> wrote:
In my AP Comp. class, we wrote a Symbolic Algebra program in Java that
is completely based on one interface: IExpression.
I want to port my Java code to C++, for experience, and I'm having a
few issues.
C++ doesn't (to my knowledge) have an equivalent of an Interface, so
I;
class IExpression {
public:
        IExpression() {};
        virtual bool hasVar() ;
        virtual double eval(double);
        virtual string getStr();
        virtual string getSmart();
        virtual bool equals(IExpression&);
        virtual IExpression simplify();
        virtual IExpression derivative();
};
Once the "interface" or base-class was done, I wanted to implement it
with a simple class from my project: Number;
class Number : public virtual IExpression {
    private:
        double value;
        void init();
    public:
        Number(double);
        bool equals(Number &that);
        bool hasVar();
        double eval(double);
        string getStr();
        string getSmart();
        bool equals(IExpression&);
        IExpression simplify();
        IExpression derivative();
};
I wrote the implementation of Number's methods in the header, and I
wont bother posting (most of) them.
The one that's giving me hell is;
bool Number::equals(IExpression &that) {
    if (typeid(this) == typeid(that)) {
        return this->equals(reinterpret_cast<Number&> (that));
    } else {
        return false;
    }
}
bool Number::equals(Number &that) {
    return this->value == that.value;
}
C++ has given me arcane error messages, and I don't know what I'm
doing that's so horribly incorrect.
I think it's a down-casting problem in equals(), but it's also telling
me that I have an "undefined reference to vtable".
How can I fix this?
1) IExpression, in all probability, needs a virtual destructor.
2) As it stands, every member-function (method) in IExpression needs to 
be defined. If you don't want to define them (because this is an 
interface after all) you need to put "=0" between the ')' and the ';'. 
As in:
   virtual bool hasVar() = 0;
3) 'simplify()' and 'derivative()' both return IExpressions by value, 
that is probably wrong. If these function are supposed to return some 
sub-type of IExpression, they need to be returning by pointer or 
reference. In that case, be careful not to return a pointer/reference to 
a temporary variable.
4) Number::equals() should use dynamic_cast, since you mention Java, you 
can think of it like this:
   // Java
   boolean result = false;
   Number n = (Number)that;
   if (n != null)
      result = equals(n);
   return result;
   // C++
   bool result = false;
   Number* n = dynamic_cast<Number*>(&that);
   if (n)
      result = equals(*n);
   return result;
The above are the outright errors in the code. Design issues include 
1) const correctness
2) The fact that you are using a cast in the first place. After all, 
according to the above, the number '5' is not equal to the expression '2 
+ 3'. Is that really what you want?
3) C++ and Java have very different philosophies, especially when it 
comes to object creation a straight port probably isn't wise. You would 
learn more by attempting to re-implement the behavior of the Java 
program in C++ without trying to directly port the code.