Loom
Loom

Reputation: 9996

Forward declaration of derived inner class

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.

Upvotes: 2

Views: 242

Answers (3)

BЈовић
BЈовић

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

Wolf
Wolf

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

molbdnilo
molbdnilo

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

Related Questions