私有继承的typedef对嵌套类的可见性

bel*_*daz 8 c++ inheritance typedef nested-class

在下面的例子中(道歉为长度)我试图隔离一些在私有继承自另一个类的类中使用嵌套类时遇到的意外行为.我经常看到这样的陈述:与未使用的类相比,嵌套类没有什么特别之处,但是在这个例子中可以看到嵌套类(至少根据GCC 4.4)可以看到一个嵌套类的公共类型定义由结束类私有继承的类.

我很欣赏typdef与成员数据不一样,但我发现这种行为令人惊讶,我想其他许多人也会这样.所以我的问题是双重的:

  1. 这是标准行为吗?(一个很好的解释为什么会非常有帮助)
  2. 人们可以期望它适用于大多数现代编译器(即,它有多便携)?

#include <iostream>

class Base {
  typedef int priv_t;
  priv_t priv;
public:
  typedef int pub_t;
  pub_t pub;
  Base() : priv(0), pub(1) {}
};

class PubDerived : public Base {
public:
  // Not allowed since Base::priv is private
  // void foo() {std::cout << priv << "\n";}

  class Nested {
    // Not allowed since Nested has no access to PubDerived member data
    // void foo() {std::cout << pub << "\n";}

    // Not allowed since typedef Base::priv_t is private
    // void bar() {priv_t x=0; std::cout << x << "\n";}
  };

};

class PrivDerived : private Base {
public:
  // Allowed since Base::pub is public
  void foo() {std::cout << pub << "\n";}

  class Nested {
  public:
    // Works (gcc 4.4 - see below)
    void fred() {pub_t x=0; std::cout << x << "\n";}
  };
};

int main() {

  // Not allowed since typedef Base::priv_t private
  // std::cout << PubDerived::priv_t(0) << "\n";

  // Allowed since typedef Base::pub_t is inaccessible
  std::cout << PubDerived::pub_t(0) << "\n"; // Prints 0

  // Not allowed since typedef Base::pub_t is inaccessible
  //std::cout << PrivDerived::pub_t(0) << "\n";

  // Works (gcc 4.4)
  PrivDerived::Nested o;
  o.fred(); // Prints 0
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 4

前言:在下面的答案中我提到了C++98和C++03之间的一些区别。然而,事实证明我正在谈论的更改尚未成为标准,因此 C++03 在这方面与 C++98 并没有真正的不同(感谢 Johannes 指出这一点)。不知怎的,我确信我在 C++03 中看到过它,但实际上它不在那里。然而,这个问题确实存在(请参阅 Johannes 评论中的 DR 参考),并且一些编译器已经实现了他们可能认为是该问题最合理的解决方案。因此,下面的文本中对 C++03 的引用是不正确的。请将对 C++03 的引用解释为对此行为的某些假设但很可能是未来规范的引用,一些编译器已经在尝试实现该规范。


值得注意的是,C++98 和 C++03 标准之间的嵌套类访问权限发生了重大变化。

在 C++98 中,嵌套类对封闭类的成员没有特殊的访问权限。它基本上是完全独立的类,只是在封闭类的范围内声明。它只能访问封闭类的公共成员。

在 C++03 中,嵌套类作为封闭类的成员被授予对封闭类成员的访问权限。更准确地说,嵌套类被赋予与封闭类的静态成员函数相同的访问权限。即现在嵌套类可以访问封闭类的任何成员,包括私有成员。

因此,您可能会观察到不同编译器和同一编译器版本之间的差异,具体取决于它们实现新规范的时间。

当然,您必须记住,嵌套类的对象不以任何方式与封闭类的任何特定对象绑定。就实际对象而言,这是两个独立的类。为了从嵌套类访问封闭类的非静态数据成员或方法,您必须拥有封闭类的特定对象。换句话说,嵌套类的行为确实就像封闭类的静态成员函数一样:它没有this封闭类的特定指针,因此它无法访问封闭类的非静态成员,除非你努力给它一个封闭类的特定对象来访问。如果没有它,嵌套类只能访问封闭类的 typedef 名称、枚举和静态成员。

说明 C++98 和 C++03 之间差异的简单示例可能如下所示

class E {
  enum Foo { A };
public:
  enum Bar { B };

  class I {
    Foo i; // OK in C++03, error in C++98
    Bar j; // OK in C++03, OK in C++98
  };
};
Run Code Online (Sandbox Code Playgroud)

此更改正是允许您的PrivDerived::Nested::fred函数编译的原因。它无法通过迂腐的 C++98 编译器的编译。