类中的内部成员可见性

Inner member visibility in class

本文关键字:成员 可见性 内部      更新时间:2023-10-16

根据C++标准,

9.2[class.mem]:

类被视为完全定义的对象类型(3.9)(或完整类型)。在类成员规范,该类在函数体,默认参数,使用引入继承构造函数(12.9)、异常规范和非静态数据成员(包括嵌套类中的此类事物)。否则视为不完整在其自己的类成员规范内

因此,下面的代码应该编译,事实上它确实进行了

struct Foo{
     Foo()
     {
        Bar bar; // Bar is fully visible here, even though it's defined later
     }
     //void f(Bar){} // But NOT VISIBLE if used as a function parameter
     struct Bar{};
};
int main()
{
    Foo foo;
}

在Coliru上直播

但是,如果我取消注释定义成员函数void Foo::f(Bar)的行,则代码编译失败,并出现错误

错误:"Bar"尚未声明为

再次阅读标准,函数参数似乎确实不被视为类完整的地方。然而,这根本没有任何意义。你能解释一下为什么在函数参数完全定义之前,我不能在函数参数中使用Bar(但在其他情况下,我可以在函数内部完全使用它,而不会有任何问题)吗?

9.2[class.mem]中列出的所有情况下,知道类型可以推迟到类完全定义为止。我们可以在缺陷报告643中看到这一基本原理:在类成员规范中使用decltype,其中写道:

在其他情况下,如果类类型在类的定义中被认为是完整的,则可以将处理构造推迟到定义结束。这对于类型来说是不可能的,因为在随后的声明中可能会立即需要该类型。

正如T.C.所指出的,缺陷报告325也涉及查找问题:默认参数何时解析?并且缺陷报告1352进行处理。后面的一个还提到了能够推迟解析直到类完成的相同技术:

关于类作用域和类何时被认为是完整的规则(通常通过延迟解析类成员声明的部分来实现)是不一致的,需要澄清。

根据03标准,3.4.1/8(不合格名称查找):

定义X类成员函数(9.3)时使用的名称,该函数的声明符id29)应以以下方式之一声明:

--在使用它的块中或在封闭块(6.3)中使用之前,或

--应为X类成员或X(10.2)基本类成员,或

--如果X是Y类(9.7)的嵌套类,则应是Y的成员,或者应是Y基类的成员(此查找依次应用于Y的封闭类,从最里面的封闭类开始),30)或

--如果X是局部类(9.8)或是局部类的嵌套类,则在块中定义类X之前包含X类或的定义

--如果X是命名空间N的成员,或者是作为N成员的类的嵌套类,或者是本地类或者是作为N的成员的函数的局部类中的嵌套类定义,在名称空间N中或在N的封闭名称空间之一中