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