"Alf P. Steinbach" <al***@start.no> wrote in message
class X
class Y : public X
class A
{
public:
virtual X* f() const;
X* fX() const;
};
class B : public A
{
public:
virtual X* f() const;
Y* fY();
};
A* X::gA() const { return g(); }
B* Y::gB() const { return static_cast<B*>( g() ); }
X* A::fX() const { return f(); }
Y* B::fY() const { return static_cast<Y*>( f() ); }
This is a great idea. One can use it for user types. Say the base class
returns a shared_ptr<X> and the derived class returns a shared_ptr<Y>, which
we know is covariant but the compiler doesn't.
Only thing I've done in the past is to to rename fX() and fY() to f(). So
my class looks like this:
class A
{
private/protected:
virtual X* dof() const;
public:
counted_ptr<X> f() const { return dof(); }
};
class B : public A
{
private/protected:
virtual X* dof() const;
public:
counted_ptr<Y> f() const { return static_cast<Y*>(dof()); }
};
But wait a sec. I've violated the guideline that you ought not to override
a non-virtual function. In general, this is a fine rule that we ought to
respect. Because when we call a function from a pointer to the base class,
the system ought to call the derived class function -- and the most popular
example of this is the virtual destructor.
But in the above class design, we are calling the derived class function,
namely dof(). It's just that A::f() casts the return type to something
class A knows about, namely an X* or counted_ptr<X>. Presumably A.h
includes X.h or forward declares class X. And B::f() also calls the derived
class function, namely dof() again. Assuming B::dof() returns an object
that is Y or higher cast as an X*, it's perfectly OK for B::f() to cast this
to a counted_ptr<Y>. It's the same object after all.
So when we follow the above idiom, it seems perfectly OK to break the
guideline that you ought not to override a non-virtual function. Any
thoughts?