bernied@yoyodyne.ncsa.uiuc.edu (Bernhard Damberger) (06/02/91)
I 'am having some problems with virtual operators...maybe some
one out there can help me. I have a class (called Base) that acts as a base
class for all other classes. Base has all the relational operators defined
(<, >, <=, etc.) as virtual. There is a subclass of Base (called TestInt) that
overides the relational operators with its own (CFront even says TestInt's
operators are hiding Base's operators). It looks something like this (some
code deleted):
class Base {
...
public:
virtual int operator< (Base &) const; // less than operator for Base
virtual int operator> (Base &) const; // greater than operator
... // etc...
};
class TestInt : public virtual Base {
...
public:
virtual int operator< (const TestInt &) const; // overide Base
virtual int operator> (const TestInt &) const; // overide Base
... // overide the rest of Base's relational operators
};
One of the things I want to do with a TestInt object (for
instance) is insert it into a binary tree class. The binary tree class is
defined as follows:
class BinaryTree : public virtual Base {
private:
int num_nodes; // number of nodes in the BinaryTree
BinaryTreeNode * root; // root of the tree
public:
...
virtual int insert (Base * object);
...
};
BinaryTreeNode is a node in the tree that contains left and
right pointers to new nodes. It also contains a pointer to a Base *. It
looks like this:
class BinaryTreeNode : public virtual Base {
// public so BinaryTree can access members. Maybe make BinaryTree a friend?
public:
BinaryTreeNode *left; // pointer to the left Node
BinaryTreeNode *right; // pointer to the right Node
BinaryTreeNode *parent; // pointer to the parent Node
Base *object; // the object this node contiains
...
};
Notice BinaryTree takes in as its elements Base *. The problem
occurs when I try and use BinaryTree::insert with an TestInt object.
The code looks something like this:
int BinaryTree::insert (Base * object)
{
BinaryTreeNode *parent = NULL; // parent of current node
BinaryTreeNode *current = root; // current working node
BinaryTreeNode *new_node = new BinaryTreeNode (object);
if (new_node == NULL) return 0; // failed, return false
// find place to insert object into BTree
while (current != NULL)
{
parent = current;
if (*object < *current->object) // <-problem is here!!
current = current->left;
else current = current->right;
}
// insert object into the BinaryTree
new_node->parent = parent;
if (parent == NULL) root = new_node;
else if (*object < *parent->object) // <-problem is here!!
parent->left = new_node;
else parent->right = new_node;
this->num_nodes++; // another node was added
return 1; // return true
}
NOTE: The only elements I am inserting into the BinaryTree
(at this point) are TestInt objects.
The problem occurs when the "less than" operator is applied. I
want CFront to call the most specific operator< as possible. In this
case that would mean if I called BinaryTree::insert(foo), where foo is
a TestInt pointer, I would want CFront to call TestInt::operator<(TestInt &)
But, instead it calls the more basic Base::operator< (instead of
TestInt::operator<). I have tried using the more "specific" notation,
object->operator<(Base *), but I still get the same results.
I also tried using pointers instead of references, but it still called
Base::operator<.
So how do I get CFront to use the virtual operators? When are
the types bound (it looks like at compile time instead of run time)?
How do I get CFront to call the most specific operator method?
Any suggestions would be appreciated how to approach this
problem. Thanks in advance.
Bernhard Damberger
bernied@yoyodyne.ncsa.uiuc.edusarima@tdatirv.UUCP (Stanley Friesen) (06/04/91)
I think this is getting to FAQ level. In article <1991Jun1.175904.20181@ux1.cso.uiuc.edu> bernied@yoyodyne.ncsa.uiuc.edu (Bernhard Damberger) writes: > > I 'am having some problems with virtual operators... >class Base { > ... >public: > virtual int operator< (Base &) const; // less than operator for Base > virtual int operator> (Base &) const; // greater than operator > ... // etc... >}; > >class TestInt : public virtual Base { > ... >public: > virtual int operator< (const TestInt &) const; // overide Base > virtual int operator> (const TestInt &) const; // overide Base > ... // overide the rest of Base's relational operators >}; OK, here's your problem. These do *not*, I repeat, *not*, override the "corresponding" virtual functions in Base! And why not? Because they do not have *exactly* *matching* signatures. By making the parameters 'const TestInt &' instead of 'Base &' you are *replacing*, not overriding, the functions in Base. Now, since the functions in Base have never been overridden, then a call through a Base pointer or reference will, naturally, use the pre-defined base functions. <<Irrelevant detail deleted>> > The problem occurs when the "less than" operator is applied. I >want CFront to call the most specific operator< as possible. In this >case that would mean if I called BinaryTree::insert(foo), where foo is >a TestInt pointer, I would want CFront to call TestInt::operator<(TestInt &) >But, instead it calls the more basic Base::operator< (instead of >TestInt::operator<). As indeed it should, given the above definitions. > So how do I get CFront to use the virtual operators? When are >the types bound (it looks like at compile time instead of run time)? >How do I get CFront to call the most specific operator method? This is quite simple, make the TestInt relational functions take parameters of type (Base &). Oh, you need 'const' parameters? Then you need to add the const qualified forms as virtual functions in the definition of class Base. -- --------------- uunet!tdatirv!sarima (Stanley Friesen)
mittle@blinn.watson.ibm.com (Josh Mittleman) (06/04/91)
In article <1991Jun1.175904.20181@ux1.cso.uiuc.edu>, bernied@yoyodyne.ncsa.uiuc.edu (Bernhard Damberger) writes: > > I 'am having some problems with virtual operators...maybe some > one out there can help me. I have a class (called Base) that acts as a base > class for all other classes. Base has all the relational operators defined > (<, >, <=, etc.) as virtual. There is a subclass of Base (called TestInt) that > overides the relational operators with its own (CFront even says TestInt's > operators are hiding Base's operators). It looks something like this (some > code deleted): Without reading any further, it is pretty clear what your problem is. Virtual functions must have identical signatures. Subclass::operator<(Subclass&) is not the same signature as BaseClass::operator<(BaseClass&), and the virtual function mechanism will not see a match. To get the virtual behavior, the Subclass function must have the signature Subclass::operator<(BaseClass&). When your compiler tells you that TestInt's operators are hiding Base's operators, that is a warning of a probable error. It means that TestInt's operators are not being treated as virtual functions. =========================================================================== Josh Mittleman (mittle@watson.ibm.com or joshua@paul.rutgers.edu) J2-C28 T.J. Watson Research Center, PO Box 704, Yorktown Heights, NY 10598