Suppose I have these abstract classes Foo
and Bar
:
class Foo;
class Bar;
class Foo
{
public:
virtual Bar* bar() = 0;
};
class Bar
{
public:
virtual Foo* foo() = 0;
};
Suppose further that I have the derived class ConcreteFoo
and ConcreteBar
. I want to covariantly refine the return type of the foo()
and bar()
methods like this:
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
};
This won't compile since our beloved single pass compiler does not know that ConcreteBar
will inherit from Bar
, and so that ConcreteBar
is a perfectly legal covariant return type. Plain forward declaring ConcreteBar
does not work, either, since it does not tell the compiler anything about inheritance.
Is this a shortcoming of C++ I'll have to live with or is there actually a way around this dilemma?
To write a forward declaration for a function, we use a declaration statement called a function prototype. The function prototype consists of the function header (the function's return type, name, and parameter types), terminated with a semicolon. The function body is not included in the prototype.
In Objective-C, classes and protocols can be forward-declared if you only need to use them as part of an object pointer type, e.g. MyClass * or id<MyProtocol>.
In C++, a variable declaration must be prefixed with extern : extern A Unit[10]; // ... A Unit[10] = { ... }; (Note that in C++ you can omit the leading struct .)
A forward declaration is much faster to parse than a whole header file that itself may include even more header files. Also, if you change something in the header file for class B, everything including that header will have to be recompiled.
You can fake it quite easily, but you lose the static type checking. If you replace the dynamic_casts
by static_casts
, you have what the compiler is using internally, but you have no dynamic nor static type check:
class Foo;
class Bar;
class Foo
{
public:
Bar* bar();
protected:
virtual Bar* doBar();
};
class Bar;
{
public:
Foo* foo();
public:
virtual Foo* doFoo();
};
inline Bar* Foo::bar() { return doBar(); }
inline Foo* Bar::foo() { return doFoo(); }
class ConcreteFoo;
class ConcreteBar;
class ConcreteFoo : public Foo
{
public:
ConcreteBar* bar();
protected:
Bar* doBar();
};
class ConcreteBar : public Bar
{
public:
ConcreteFoo* foo();
public:
Foo* doFoo();
};
inline ConcreteBar* ConcreteFoo::bar() { return &dynamic_cast<ConcreteBar&>(*doBar()); }
inline ConcreteFoo* ConcreteBar::foo() { return &dynamic_cast<ConcreteFoo&>(*doFoo()); }
Doesn't static polymorphism solve your problem? Feeding the base class with the derived class through template argument? So the base class will know the derivative Type and declare a proper virtual?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With