【问题标题】:C++ Have One Nested Class Inherit From Another Nested ClassC++ 有一个嵌套类继承自另一个嵌套类
【发布时间】:2013-01-25 02:22:51
【问题描述】:

我正在编写一个跨平台的类层次结构,并希望将依赖于平台的实现保留在它们自己的类中(而不是拥有一个具有#ifdefs 的类)。这是我到目前为止所拥有的,但编译器抱怨BaseDef 是私有的。对于如何在编译它的同时保持这个基本结构的任何帮助将不胜感激:-)

编辑:here 看来这是不可能的。还有什么其他方法可以保持这个一般结构并仍然编译吗?

根.h

class Root {
    private:
        class BaseDef {
            virtual void foo() = 0;
            virtual void bar() = 0;
        };

        #ifdef _WIN32
        class WinImp;
        #else
        class NixImp;
        #endif

        BaseDef* imp;

        BaseDef* getImp();

    public:
        Root() : imp(getImp()) {}
        void foo();
        void bar();
};

根.cpp

#include "Root.h"
void Root::foo() {
    imp->foo();
}

void Root::bar() {
    imp->bar();
}

WinImp.h

#ifdef _WIN32
#include "Root.h"
class WinImp : public Root::BaseDef {
    public:
        void foo();
        void bar();
};
#endif

WinImp.cpp

#include "WinImp.h"
#ifdef _WIN32
    Root::WinImp::foo() {

    }

    Root::WinImp::bar() {

    }

    Root::BaseDef* Root::getImp() {
        return new Root::WinImp();
    }
#endif

【问题讨论】:

  • 确认...使用单例实例作为具有静态成员的命名空间...更好地使用命名空间。
  • @Potatoswatter 这已将我的所有代码都从其中剥离(显然:-))....实际上它不能是命名空间

标签: c++ oop inheritance nested-class


【解决方案1】:

您的主要问题是BaseDef 是私有的。这意味着其他类(除了 Root 本身)无法访问 BaseDef 名称。一种方法是公开BaseDef。或者,您可以使派生类(WinImpNixImp)成为 Root 的朋友,以便他们可以访问 BaseDef 名称。另外Root不能访问BaseDef的成员,所以他们需要公开或者让Root成为BaseDef的朋友。

class Root {
private:
  class BaseDef {
  public:
    // These need to be public so that Root can see them or Root needs to be a friend. 
    //Nothing else can see BaseDef though so this is safe.
    virtual void foo() = 0;
    virtual void bar() = 0;
  };

  class WinImp; // Forward declare the classes
  friend class WinImp; // And then make them friends
  class NixImp;
  friend class NixImp;

  BaseDef* imp;

  BaseDef* getImp();

public:
  Root() : imp(getImp()) {}
  void foo();
  void bar();
};

void Root::foo() {
  imp->foo();
}

void Root::bar() {
  imp->bar();
}

// Since this is a nested class i made it Root::WinImp
class Root::WinImp : public Root::BaseDef {
public:
  void foo();
  void bar();
};

void Root::WinImp::foo() {}

void Root::WinImp::bar() {}

Root::BaseDef* Root::getImp() {
  return new WinImp();
}

根据 2003 标准 (11.4.p2),此方法是不允许的,但在 C++11(相同示例)中,它是明确允许的 (11.3.p2)。但是,即使在 2003 模式下,clang(经过 3.1 测试)也接受了这一点。 gcc(4.7.2 测试)接受这一点(即使在 2003 模式下),只要派生类嵌套在同一个类内,但如果在类外则不会。

【讨论】:

  • 我最初认为这会起作用,但它仍然无法编译。见cboard.cprogramming.com/cplusplus-programming/…
  • @Eliezer 它在这里编译得很好,包含我建议的更改的所有组合(使用 clang 3.1)。在那种情况下,我似乎发现了一个编译器错误。如果我找到更好的方法,我会更新我的答案。
  • @Eliezer 我想我知道问题出在哪里。引用的规格是 2003 年版。我使用的编译器是 2011。该网站上的引用在 2003 标准中是正确的,但 2011 规范 11.3.p2 的等效部分似乎明确允许我写的内容。如果您有最新的编译器,您可能想尝试添加适当的选项以支持 C++11(如果可用)。
  • 很遗憾,2003 年无法做到这一点。我会尝试切换编译器
  • 我使用的是 clang 3.1。发现了一些因您使用 _WIN32 而我不在 Windows 上而隐藏的问题。我把这些东西留在了标题中,但我没有为了实现而复制它。最终结果是我从class XXXImp 更改为friend class XXXImp 使Imp 类成为全局类而不是嵌套类。由于您的 WinImp 错误地也是全球性的,因此它被接受了。但最终结果是,在修复了您的错误和我的错误复制之后,结果证明 clang 可以正确嵌套和全局工作。 gcc 只接受它们嵌套。将更新我的答案。
【解决方案2】:

它抱怨BaseDefprivate...

class Root {
    private:
        class BaseDef {
            virtual void foo() = 0;
            virtual void bar() = 0;
        };

那就公开吧……

class Root {
    public:
        class BaseDef {
            virtual void foo() = 0;
            virtual void bar() = 0;
        };

脚注:

你试图避免#ifdef,所以摆脱这个:

#ifdef _WIN32
class WinImp;
#else
class NixImp;
#endif

相反,只使用一个类:

class Imp;

【讨论】:

  • 我不希望任何人能够访问BaseDef。我想保留WinImpNixImp 主要是为了便于阅读。我将在Root 中使用#ifdef,因为那里不应该有任何维护
  • 作为将BaseDef 公开的替代方法,您可以将实现类(WinImpNixImp)设为Root 的朋友。这将允许他们访问Root 的私有成员,包括BaseDef
  • 所以嵌套类默认不是朋友?
  • @Eliezer 不。他们就像任何其他班级一样。这也是为什么您会收到关于 BaseDef 私密的投诉。
  • @John5342 谢谢。我会试试的。你想把它放在答案中以便我给你吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
相关资源
最近更新 更多