无法从多态嵌套 classes 访问包含 class 的成员

Unable to access members of including class from a polymorphic nested classes

嵌套的 class Foo::Utility 可以访问另一个嵌套的 class Foo::Container,即使后者是私有的。我正在尝试将此访问权限扩展到 Foo::Utility 的多态版本 UtilityPrint 但没有成功:

class Foo {
private:
  class Container {};

public:
  class Utility {
  public:
    virtual void action(Container &) = 0;
    // works even if Container is private
  };

  Container container;
  Utility * utility;

  Foo(Utility * utility): container(), utility(utility) {};

  void performAction() {
    utility -> action(container);
  }
};

// polymorphic nested class
// failed attempt
class UtilityPrint : Foo::Utility {
public:
  virtual void action(Foo::Container &) {
    /* Implementation */

    // this does not work, because Foo::Container is private
  }
};

是否有实现此目的的正确方法,或者这是不是一个坏主意?

我得到的错误信息是这样的:

error: ‘class Foo::Container’ is private
   class Container {};
         ^
error: within this context
   virtual void action(Foo::Container &) {

此外,这是我使用这种有点奇怪的设计的原因: 我想要一个 container 和一个对容器和 Foo 都起作用的多态 utility。由于 containerutility 都只会在 Foo 的上下文中使用,我将两个 class 放入 Foo.


编辑:我可以将派生的 Utility 包装在派生的 Foo 中,然后代码编译:

class Foo {
protected:
  class Container {};

public:
  class Utility {
  public:
    virtual void action(Container &) = 0;
  };

  Container container;
  Utility * utility;

  Foo(Utility * utility): container(), utility(utility) {};

  void performAction() {
    utility -> action(container);
  }
};

class FooPrint : public Foo {

public:
  class Utility : Foo::Utility {
  public:
    virtual void action(Foo::Container &) {
      /* Implementation */
    }
  };

};

然而,这引入了一个包装器 class FooPrint,它仅出于句法原因而存在,并且(作为派生的 class!)永远不会被实例化。由于这个原因,我不喜欢这种方法,但在这方面我可能会大错特错。

访问权限不继承。这在讨论friends时更常被提及,但在这里也适用。

先来看看为什么Foo::Utility::action可以访问私有classFoo::Container。实际上,它就在名字中。 Foo::Container只能被Foo的成员访问,而Foo的成员只要写出以“Foo::”开头的限定名即可识别。

相比之下,UtilityPrint 不是 Foo 的成员。 (事实上​​ ,如果有人可以简单地说 "oh, yeah, I'm a member too!" 并获得您的私人信息,那将是一个巨大的安全违规行为。)所以虽然 UtilityPrint 已经(受保护) 访问 Foo::Utility,它无法访问 Foo::Utility 可以访问的所有内容。

如果 Foo::Utility 希望扩展对从它派生的 classes 的访问,则需要明确地这样做。一种方法是创建一个别名。

class Utility {
  protected:
    using Container = Foo::Container;  // Derived classes can access this.
  public:
    virtual void action(Container &) = 0;
    virtual ~Utility() {}  // <-- remember to properly support polymorphism 
};

这是否是一个好的设计仍然悬而未决。我会认为这是一个警告标志,表明可能存在某些问题,但并非最终如此。这个问题没有足够的背景让我做出这样的决定。我只想给你一个指导方针,如果你觉得你正在规避很多语言功能(比如私人访问),那么也许设计需要改进。

我采纳了this solution:

class Foo {
protected:
  class Container {};

public:
  class Utility {
  protected:
    typedef Container FooContainer;

  public:
    virtual void action(Container &) = 0;
  };

  Container container;
  Utility * utility;

  Foo(Utility * utility): container(), utility(utility) {};

  void performAction() {
    utility -> action(container);
  }
};

class UtilityPrint : Foo::Utility {
public:
  virtual void action(FooContainer &) {
    /* implementation */
  }
};

当使用 typedef 引入名称 FooContainer 时,可访问性仅应用于该名称,而不考虑它实际上指的是 Foo::Container。这允许所有派生的 Utility 通过命名 FooContainer.

来引用 Foo::Container

我相信这也适用于 using