Предварительное объявление производного внутреннего класса

Я столкнулся с проблемой реализации некоторых вариантов заводского метода.

// 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();
    };
    

    Однако этот обходной путь не является приемлемым

2

Решение

Нет, вы не можете заранее объявить что-то подклассом.

Конечно, поскольку вы все равно будете скрывать детали класса, вы можете добавить еще один уровень косвенности.

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;
}
1

Другие решения

Конечно, вы можете сделать предварительное объявление встроенного класса. Но тогда отношение 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 */
};
0

Вам даже не нужно объявлять подтип 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. Там нет способов обойти это.

0
По вопросам рекламы [email protected]