Reputation: 9996
I ran into problem implementing some variations of factory method.
// from IFoo.h
struct IFoo {
struct IBar {
virtual ~IBar() = 0;
virtual void someMethod() = 0;
};
virtual IBar *createBar() = 0;
};
// from Foo.h
struct Foo : IFoo { // implementation of Foo, Bar in Foo.cpp
struct Bar : IBar {
virtual ~Bar();
virtual void someMethod();
};
virtual Bar *createBar(); // implemented in Foo.cpp
};
I'd like to place declaration of Foo::Bar in Foo.cpp
. For now I cannot succeed:
struct Foo : IFoo {
//struct Bar; //1. error: invalid covariant return type
// for ‘virtual Foo::Bar* Foo::createBar()’
//struct Bar : IBar; //2. error: expected ‘{’ before ‘;’ token
virtual Bar *createBar();
// virtual IBar *createBar(); // Is not acceptable by-design
};
Is there a trick to have just forward declaration of Boo
in Foo.hpp
and to have full declaration in Foo.cpp
?
EDIT: Looks like, I didn't show errors clear. Sо, there are samples in greater detail.
First trying of forward declaration:
struct Foo : IFoo {
struct Bar;
virtual Bar *createBar(); //<- Compile-error
};
//error: invalid covariant return type for ‘virtual Foo::Bar* Foo::createBar()’
Second trying of forward declaration:
struct Foo : IFoo {
struct Bar : IBar; //<- Compile-error
virtual Bar *createBar();
};
// error: expected ‘{’ before ‘;’ token
Someone can offer to change return type for createBar
(from Bar
to IBar
)
struct Foo : IFoo {
virtual IBar *createBar();
};
However, this workaround is not acceptable by-design
Upvotes: 2
Views: 242
Reputation: 64283
You do not need to even declare Bar subtype in the Foo class. The Bar can be completely hidden in the source file.
This example demonstrates what I mean :
#include <functional>
#include <iostream>
#include <utility>
struct IFoo {
struct IBar {
virtual ~IBar(){}
virtual void someMethod() = 0;
};
virtual IBar *createBar() = 0;
};
// from Foo.h
struct Foo : IFoo { // implementation of Foo, Bar in Foo.cpp
virtual IBar *createBar(); // implemented in Foo.cpp
};
namespace {
struct HiddenBar : IFoo::IBar
{
virtual void someMethod(){
std::cout<<"I am IBar type"<<std::endl;
}
};
}
IFoo::IBar* Foo::createBar()
{
return new HiddenBar;
}
int main() {
Foo foo;
auto bar = foo.createBar();
bar->someMethod();
}
Take a note that the HiddenBar should be invisible to the outside world, and accessible only through it's interface. But that means fixing the signature of the Foo::createBar()
method.
The alternative is to fully declare Foo::Bar in Foo. There are no ways around it.
Upvotes: 0
Reputation: 10236
Of course, you can do a forward declaration of an embedded class. But then the is-a relation of Bar and IFoo::IBar is only accessible in the implementation file Foo.cpp.
Foo.h:
struct Foo : IFoo {
struct Bar;
virtual IBar *createBar();
};
Foo.cpp:
struct FooBar::Bar
{
/* define the nested class here */
};
Upvotes: 0
Reputation: 66459
No, you can't forward declare something being a subclass.
Of course, since you're going to hide the class details anyway, you could add another level of indirection.
struct IFoo {
struct IBar {
virtual ~IBar() = 0;
virtual void someMethod() = 0;
};
virtual IBar *createBar() = 0;
};
// from Foo.h
struct Foo : IFoo {
struct Bar : IBar {};
virtual Bar *createBar();
};
// In Foo.cpp
struct FooBar : Foo::Bar
{
virtual ~FooBar() {}
virtual void someMethod()
{
// Do stuff...
}
};
Foo::Bar* Foo::createBar()
{
return new FooBar;
}
Upvotes: 1