Re: invalid covariant type / forward declaration?
* Sybolt de Boer:
Considering the following situation, is there a way to tell class White that
a Black* is actually a valid Base*? In other words can I somehow forward
declare "class Black : public Base;" in White.h and vice versa? Or am I
trying to do something very bad and clearly illegal? :)
TIA, Sybolt
// Base.h
#ifndef BASE_H
#define BASE_H
class Base {
public:
virtual Base *colleague(int i) const = 0;
virtual Base *opponent(int i) const = 0;
....
};
// White.h
#ifndef WHITE_H
#define WHITE_H
#include "Base.h"
class White : public Base {
public:
White *colleague(int i) const { return White::create(i); }
Black *opponent(int i) const { return Black::create(i); }
static White *create(int i);
....
};
// Black.h
#ifndef BLACK_H
#define BLACK_H
#include "Base.h"
class Black : public Base {
public:
Black *colleague(int i) const { return Black::create(i); }
White *opponent(int i) const { return White::create(i); }
static Black *create(int i);
....
};
The covariance support of C++ needs to know that the types are related.
You can get around it essentially as Robert Hairgrove explained else-thread, but
then when you switch to smart pointers the problem comes back with a vengeance,
because from the compiler's point of view those smart pointers are not related.
And one solution is to implement the covariance yourself. It is, after all,
nothing but a convenience notation. It's a bit more to write it yourself:
<code>
#include <memory>
#include <stdio.h>
class Base
{
public:
typedef std::auto_ptr<Base> AutoPtr;
private:
virtual AutoPtr v_colleague( int i ) const = 0;
virtual AutoPtr v_opponent( int i ) const = 0;
public:
virtual ~Base() {}
AutoPtr colleague( int i ) const { return v_colleague( i ); }
AutoPtr opponent( int i ) const { return v_opponent( i ); }
};
// These definitions are subtle due to restrictions of std::auto_ptr.
// Essentially can only be used in pure declarations until classes defined.
class White; typedef std::auto_ptr<White> AutoPtrWhite;
class Black; typedef std::auto_ptr<Black> AutoPtrBlack;
class White
: public Base
{
private:
virtual AutoPtr v_colleague( int i ) const;
virtual AutoPtr v_opponent( int i ) const;
public:
White( int i ) { printf( "Creating White(%d)\n", i ); }
virtual ~White() { printf( "White destroyed.\n" ); }
AutoPtrWhite colleague( int i ) const;
AutoPtrBlack opponent( int i ) const;
};
class Black
: public Base
{
private:
virtual AutoPtr v_colleague( int i ) const;
virtual AutoPtr v_opponent( int i ) const;
public:
Black( int i ) { printf( "Creating Black(%d)\n", i ); }
virtual ~Black() { printf( "Black destroyed.\n" ); }
AutoPtrBlack colleague( int i ) const;
AutoPtrWhite opponent( int i ) const;
};
Base::AutoPtr White::v_colleague( int i ) const
{
return AutoPtr( colleague( i ).release() );
}
Base::AutoPtr White::v_opponent( int i ) const
{
return AutoPtr( opponent( i ).release() );
}
AutoPtrWhite White::colleague( int i ) const
{
return AutoPtrWhite( new White( i ) );
}
AutoPtrBlack White::opponent( int i ) const
{
return AutoPtrBlack( new Black( i ) );
}
Base::AutoPtr Black::v_colleague( int i ) const
{
return AutoPtr( colleague( i ).release() );
}
Base::AutoPtr Black::v_opponent( int i ) const
{
return AutoPtr( opponent( i ).release() );
}
AutoPtrBlack Black::colleague( int i ) const
{
return AutoPtrBlack( new Black( i ) );
}
AutoPtrWhite Black::opponent( int i ) const
{
return AutoPtrWhite( new White( i ) );
}
int main()
{
AutoPtrWhite w( new White( 123 ) );
AutoPtrBlack b( new Black( 567 ) );
}
</code>
Cheers & hth.,
- Alf