Я столкнулся с проблемой реализации некоторых вариантов заводского метода.
// 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
};
Я хотел бы разместить объявление Foo :: Bar в Foo.cpp
, Пока я не могу добиться успеха:
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
};
Есть ли хитрость, чтобы просто объявить Boo
в Foo.hpp
и иметь полную декларацию в Foo.cpp
?
РЕДАКТИРОВАТЬ: Похоже, я не показал ошибки ясно. Так, есть образцы более подробно.
Первая попытка предварительной декларации:
struct Foo : IFoo {
struct Bar;
virtual Bar *createBar(); //<- Compile-error
};
//error: invalid covariant return type for ‘virtual Foo::Bar* Foo::createBar()’
Вторая попытка предварительной декларации:
struct Foo : IFoo {
struct Bar : IBar; //<- Compile-error
virtual Bar *createBar();
};
// error: expected ‘{’ before ‘;’ token
Кто-то может предложить изменить тип возврата для createBar
(от Bar
в IBar
)
struct Foo : IFoo {
virtual IBar *createBar();
};
Однако этот обходной путь не является приемлемым
Нет, вы не можете заранее объявить что-то подклассом.
Конечно, поскольку вы все равно будете скрывать детали класса, вы можете добавить еще один уровень косвенности.
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;
}
Конечно, вы можете сделать предварительное объявление встроенного класса. Но тогда отношение is-a Bar и IFoo :: IBar доступно только в файле реализации Foo.cpp.
foo.h:
struct Foo : IFoo {
struct Bar;
virtual IBar *createBar();
};
foo.cpp:
struct FooBar::Bar
{
/* define the nested class here */
};
Вам даже не нужно объявлять подтип Bar в классе Foo. Панель может быть полностью скрыта в исходном файле.
Этот пример демонстрирует, что я имею в виду:
#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.cppvirtual 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();
}
Обратите внимание, что HiddenBar должен быть невидим для внешнего мира и доступен только через его интерфейс. Но это означает исправление подписи Foo::createBar()
метод.
Альтернатива — полностью объявить Foo :: Bar в Foo. Там нет способов обойти это.