Re: c++ polymorphism and function overloading
On Aug 23, 8:21 am, jungleman <ustcrevolution...@gmail.com> wrote:
I have some problems in the following examples:
// where code begins
class base
{
public:
virtual bool operator == (const base& b) const = 0;
}
class inheritanceA
{
public:
virtual bool operator == (const inheritanceA& b) const
{cout << "operator == in inheritanceA"}
}
class inheritanceB
{
public:
virtual bool operator == (const inheritanceB& b) const
{cout << "operator == in inheritanceB"}
}
int main()
{
base* a = new inheritanceA;
base* b = new inheritanceB;
cout << (*a)==(*b) << endl;
return 0;
}
problems coming:
but the codes above is wrong while compiling, if I change the method
function in class inheritanceA, virtual bool operator==(const base&
b), It will be Ok.
however, when I add a data base* c = new inheritanceB, and invokes
operator == like this: (*a)==(*c), It will invokes method operator ==
in class inheritanceA,
but what I want is the compiler says it to be wrong .
In addition to Christian Hackl's comments: (*a) == (*c) cannot
be a compile-time error, since the compiler has no way of
knowing the dynamic types (which may vary dynamically---that's
the whole point of polymorphism, after all).
What you're really trying to do requires double dispatch; i.e.
for operator== to be polymorphic on both it's arguments.
Depending on the situation, there are three possible solutions
(that I know, at least):
The first is limited to the case where you always return false
if the two dynamic types are distinct:
class Base
{
virtual bool isEqual( Base const& other ) const = 0;
public:
bool operator==( Base const& other ) const // NOT virtual
{
return typeid( *this ) == typeid( other )
&& isEqual( other );
}
};
class Derived : public Base
{
virtual bool isEqual( Base const& other ) const
{
Derived const* pOther = dynamic_cast<Derived const*>( &other );
assert( pOther != NULL );
// compare data in *pOther and *this...
}
};
The second is the "classical" solution:
class Base
{
virtual bool isEqual( Derived1 const& other ) const
{
return false;
}
virtual bool isEqual( Derived2 const& other ) const
{
return false;
}
// etc., one for each possible derived class.
virtual bool isEqual( Base const& other ) const = 0;
public:
bool operator==( Base const& other ) const
{
return isEqual( other );
}
};
class Derived1 : public Base
{
virtual bool isEqual( Derived1 const& other ) const
{
// comparison for two Derived...
}
virtual bool isEqual( Derived2 const& other ) const
{
// if this makes sense, and can ever return true...
}
virtual bool isEqual( Base const& other ) const
{
return isEqual( *this );
}
};
This handles double dispatch very effectively, but it requires
that the base class know all of the derived classes. Which is
fine for closed hierarchies (where I've actually used it
effectively), but not generally. It does avoid any dynamic_cast
or other use of RTTI (other than resolving the virtual
functions).
The third requires some additional work, but is the most
general:
class Base
{
struct TypePair
{
std::type_index lhs;
std::type_index rhs;
TypePair( std::type_info const& lhs, std::type_info const& rhs )
: lhs( lhs )
, rhs( rhs )
{
}
TypePair( Base const& lhs, Base const& rhs )
: lhs( typeid( lhs ) )
, rhs( typeid( rhs ) )
{
}
bool operator<( TypePair const& other ) const
{
return lhs != other.lhs
? lsh < other.lsh
: rhs < other.rhs;
}
};
typedef std::map<TypePair, bool (*)(Base const&, Base const&)>
EqMap;
static EqMap eqMap;
public:
bool operator==( Base const& other ) const
{
EqMap::const_iterator cmp = eqMap.find( TypePair( *this, other ) );
return cmp != eqMap.end() && (**cmp)( *this, other );
}
};
With this, you also need some means of registering all of the
comparison functions. (Remember that for n derived classes,
there are potentially 2^n comparison functions.)
--
James Kanze