Jay Nabonne wrote:
On Fri, 13 May 2005 05:56:57 -0400, Kai-Uwe Bux wrote:
Ganesh wrote:
One problem. Let's say you had this:
// interfaces are special, they do not inherit from Base
// WARNING: [this is imperative to avoid diamonds]
class IF_clone {
public:
virtual
Base* clone ( void ) const = 0;
// We have a function here with a common name.
virtual void SomeCommonlyNamedFunction() = 0;
virtual
~IF_clone ( void ) {};
};
class IF_name {
public:
virtual
std::string name ( void ) const = 0;
// We have a function here with the same common name.
virtual void SomeCommonlyNamedFunction() = 0;
virtual
~IF_name ( void ) {}
};
// the application class hierarchy:
Assuming the implementations need to be different for the two
interface methods, how would you implement class B below?
// class B implements both interfaces:
class B : public Base, public IF_clone, public IF_name {
public:
B* clone ( void ) const {
return( new B ( *this ) );
}
std::string name ( void ) const {
return( std::string( "b" ) );
}
virtual ~B ( void ) {}
};
Thanks, that's a very good point. Admittedly, I am not entirely satisfied
with what I have so far (it appears to be a little cludgy). But here is a
proposal based on disambiguation by signature. The problem that you pointed
out arises because there can be at most one method with a given name in any
class, unless their signatures differ. The idiom, below uses that:
#include <iostream>
#include <string>
#include <cassert>
// we use a universal base class:
// WARNING: [only needed for the clone method]
// this approach can yield diamond situations if
// multiple inheritance is used later on.
class Base {
public:
virtual
~Base ( void ) {};
};
// interfaces are special, they do not inherit from Base
// WARNING: [this is imperative to avoid diamonds]
// IDIOM: the last argument in each method is
// IF_<name> const & dummy = IF_<name>()
// one could have a macro doing that.
class IF_clone {
public:
IF_clone ( void ) {}
virtual
Base* clone ( IF_clone const & dummy = IF_clone() ) const {
assert( false );
};
virtual
~IF_clone ( void ) {};
};
class IF_name {
public:
IF_name ( void ) {}
virtual
std::string name ( IF_name const & dummy = IF_name() ) const {
assert( false );
};
virtual
~IF_name ( void ) {}
};
class IF_lib_name {
public:
IF_lib_name ( void ) {}
virtual
std::string name ( IF_lib_name const & dummy = IF_lib_name() ) const {
assert( false );
};
virtual
~IF_lib_name ( void ){}
};
// the interface cast:
template < typename IF,
typename Any >
IF* interface_cast ( Any * p ) {
return( dynamic_cast< IF* >( p ) );
}
// the application class hierarchy:
// class implements_interface< IF >
class A : public Base, public IF_clone {
public:
A* clone ( IF_clone const & dummy = IF_clone() ) const {
return( new A ( *this ) );
}
virtual ~A ( void ) {}
};
// class B implements both interfaces:
class B : public Base,
public IF_clone,
public IF_name,
public IF_lib_name {
public:
B* clone ( IF_clone const & dummy = IF_clone() ) const {
return( new B ( *this ) );
}
std::string name ( IF_name const & dummy = IF_name() ) const {
return( std::string( "b" ) );
}
std::string name ( IF_lib_name const & dummy = IF_lib_name() ) const {
return( std::string( "lib_B" ) );
}
virtual ~B ( void ) {}
};
int main ( void ) {
class Base * a = new A;
class Base * b = new B;
class Base * c = interface_cast< IF_clone >(b)->clone();
std::cout << ( interface_cast< IF_clone >( a ) ? true : false )
<< " "
<< ( interface_cast< IF_name >( a ) ? true : false )
<< "\n"
<< ( interface_cast< IF_clone >( b ) ? true : false )
<< " "
<< ( interface_cast< IF_name >( b ) ? true : false )
<< "\n"
<< ( interface_cast< IF_clone >( c ) ? true : false )
<< " "
<< ( interface_cast< IF_clone >( c ) ? true : false )
<< "\n";
std::cout << interface_cast< IF_name >(c)->name()
<< " "
<< interface_cast< IF_lib_name >(c)->name()
<< "\n";
}
As you can see, the client code didn't change at all.
Best
Kai-Uwe Bux