类型不完整:定义前的类用法与前向声明

Incomplete type: class usage before definition vs. forward declaration

本文关键字:用法 声明 类型 定义      更新时间:2023-10-16

我知道我们不能定义以不完整类型为参数的函数,所以下面的代码编译失败,错误C2027:使用未定义的类型"Derived"

class Derived;
class Base{
public:
   void test(Derived d){ cout<<"test"<<endl; }
};
class Derived : public Base{
   int j;
};

按照同样的逻辑,当test()获取一个Base对象时,我预计编译会失败,在那之前,该对象的类型是不完整的。然而,它并没有,下面的代码编译了精细的

class Derived;
class Base{
public:
    void test(Base b){ cout<<"test"<<endl; }
};
class Derived : public Base{
    int j;
};

在定义类时,我们所拥有的不完整类类型与正向声明所公开的不完整类型之间有区别吗?

逻辑不一样。不同之处在于,在第二个示例中,函数Base::test()使用自己类Base的对象(而不是完全外来的类Derived)。

该语言在8.3.5/6(C++03)中对这种情况进行了特殊处理

参数的类型或函数定义的返回类型除非函数定义嵌套在的成员规范中该类(包括在类)。

这个规则可以被视为另一个类似规则的"卫星",即从类成员函数、默认参数和构造函数初始值设定项列表的主体中,类类型总是被视为完整的(和完整的类型)。见9.2/2(C++03)

类在的结束}处被视为完全定义的对象类型(3.9)(或完全类型)类说明符。在类成员规范中,该类被视为函数内的完整类主体、默认参数和构造函数-构造函数初始值设定项(包括嵌套类中的这些东西)。否则它在自己的类成员规范中被认为是不完整的。

注意,在关闭}之前的所有其他上下文中,类被认为是不完整的

struct S {
  S foo(S s) // <- OK, due to 8.3.5/6
    { return s; } 
  void bar(int a = sizeof(S)) // <- OK, due to 9.2/2
    { S s; } // <- OK, due to 9.2/2
  int (*baz())[sizeof(S)] // <- ERROR: incomplete type in `sizeof`
    { return NULL; }
  void qux(int a[sizeof(S)]) // <- ERROR: incomplete type in `sizeof`
    {}
};