【问题标题】:Forward declaration of derived inner class派生内部类的前向声明
【发布时间】:2013-10-29 15:19:06
【问题描述】:

我在实现工厂方法的一些变体时遇到了问题。

// 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.cpp 中声明 Foo::Bar。现在我不能成功:

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

Foo.hpp 中仅前向声明Boo 并在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 的返回类型(从BarIBar

    struct Foo : IFoo {
      virtual IBar *createBar(); 
    };
    

    但是,这种解决方法在设计上是不可接受的

【问题讨论】:

  • 谢谢。修改后可以吗?

标签: c++ inheritance compiler-errors inner-classes forward-declaration


【解决方案1】:

不,您不能转发声明某事物为子类。

当然,既然您无论如何都要隐藏类的详细信息,您可以添加另一个间接级别。

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

【讨论】:

    【解决方案2】:

    当然,您可以对嵌入式类进行前向声明。但是 Bar 和 IFoo::IBar 的 is-a 关系只能在实现文件 Foo.cpp 中访问。

    Foo.h:

    struct Foo : IFoo {
    
        struct Bar;
    
        virtual IBar *createBar();
    };    
    

    Foo.cpp:

    struct FooBar::Bar
    {
        /* define the nested class here */
    };
    

    【讨论】:

      【解决方案3】:

      您甚至不需要在 Foo 类中声明 Bar 子类型。 Bar 可以在源文件中完全隐藏。

      这个例子说明了我的意思:

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

      请注意,HiddenBar 应该对外界不可见,并且只能通过其界面访问。但这意味着修复 Foo::createBar() 方法的签名。

      另一种方法是在 Foo 中完全声明 Foo::Bar。没有办法绕过它。

      【讨论】:

      • 谢谢。不幸的是,我无法更改 Foo::createBar() 的返回类型,因为由于设计原因,这种解决方案是不可接受的(我在这个问题中提到了这种情况)。
      • @Loom 那么你必须完全声明 Foo::Bar。
      猜你喜欢
      • 2011-11-18
      • 2020-06-04
      • 2012-06-06
      • 1970-01-01
      • 2021-05-28
      • 1970-01-01
      • 2011-04-02
      • 2016-07-25
      • 1970-01-01
      相关资源
      最近更新 更多