[comp.lang.c++] virtual operators

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.edu

sarima@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