【问题标题】:Incomplete type: class usage before definition vs. forward declaration不完整类型:定义前的类用法与前向声明
【发布时间】:2013-07-09 05:48:02
【问题描述】:

我知道我们不能定义以不完整类型作为参数的函数,因此预计以下代码无法编译并出现错误 C2027: use of undefined type '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;
};

在定义类时我们拥有的不完整类类型与前向声明暴露的不完整类型之间有区别吗?

【问题讨论】:

  • @Mat 复制构造函数和赋值运算符通常具有引用参数类型。如果将Derived d 更改为const Derived &amp; d(该参数未使用),则第一个编译失败的sn-p 会编译。你说的是相关的,但不是一回事。
  • 复制构造函数和赋值运算符将引用正在构造的类,这是合法的。但是,如果您尝试在类定义中声明一个类的对象,那将失败,对于函数参数,同样的逻辑应该是正确的。下面的@AndreyT 给出了正确的原因。

标签: c++ incomplete-type


【解决方案1】:

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

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

参数的类型或函数定义的返回类型 不应是不完整的类类型(可能是 cv 限定的),除非 函数定义嵌套在成员规范中 该类(包括定义在 类)。

这条规则可以被看作是另一个类似规则的“卫星”——这条规则表明类类型总是从类成员函数、默认参数和构造函数初始化器的主体中看到其整体(并且作为完整类型)列表。见 9.2/2 (C++03)

一个类被认为是一个完全定义的对象类型(3.9)(或完整类型),在 类说明符。在类成员规范内,类在函数内被认为是完整的 主体、默认参数和构造函数 ctor-initializers(包括嵌套类中的此类内容)。否则 它在自己的类成员规范中被认为是不完整的。

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

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`
    {}
};

【讨论】:

  • 谢谢!这让我摸不着头脑 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
相关资源
最近更新 更多