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.