2016-11-10 61 views
2

由于answer暗示,我知道允许在函数声明中使用不完整的类型作为返回值。所以我写了下面的代码:函数返回类型的前向声明

Obj.h

class Obj { 
    int x; 
}; 

f.h

class Obj; 
Obj f(); 

f.cpp

#include "Obj.h" 

Obj f() { 
    return Obj(); 
} 

使用以下编译命令

g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)

的main.cpp

#include "f.h" 
int main() { 
    f(); 
    return 0; 
}; 

编译此代码与以下编译器

g++ *.cpp 

提供了以下错误:

main.cpp: In function 'int main()': 
main.cpp:4:7: error: invalid use of incomplete type 'class Obj' 
    f(); 
    ^
f.h:1:7: error: forward declaration of 'class Obj' 
class Obj; 
    ^

因此,编译器不允许在函数声明中使用不完整类型作为返回值。什么解释?

+1

您是否将f.cpp和main.cpp编译在一起? – NathanOliver

+0

@NathanOliver我编辑了编译命令。是的,我将它们编译在一起 –

回答

1

正如您所见,并非所有不完整的类型都是允许的。实际上,规则是函数可以返回一个指针或引用为不完整的类型。原因在于,在调用的时候,编译器必须能够生成代码来处理返回的对象。当没有关于对象内容的信息时,编译器不能生成代码。例如,假设Obj有一个非平凡的析构函数;如果编译器不知道,它不能生成代码来销毁该对象。当返回类型是一个指针或引用时,编译器拥有它需要的所有信息:指针和引用通常不依赖于目标对象的细节。

2

的这里的问题是,main.cpp不知道什么Obj是那么当它编译main.cpp它不能调用f,因为返回类型是不完整的。您需要做的是将Obj的定义引入main.cpp。您可以在main.cpp中使用#include "obj.h"来完成此操作。

Live example

+0

我知道包括Obj.h将解决问题。但问题是关于函数返回类型的前向声明。我在我的问题中提到的参考文献指出,可以这样做。 –

+2

@HannaKhalil可以这么做。当你使用这个函数的时候会出现这个问题。当你使用它时,需要定义返回类型。 – NathanOliver

5

正如你说,它自己“这是允许使用不完全类型作为函数的声明返回值”。这正是编译器允许你做的。您在非定义函数声明中成功使用了不完整的返回类型 - f的声明在f.h编译时没有任何问题。

但这就是你所允许的。这不以任何方式改变的事实是:

  1. 在功能定义点的返回类型必须完整
  2. 在功能调用点的返回类型应完整。

在您的代码中,在main()里面,您尝试调用一个用不完全返回类型声明的函数。因此错误。

5.2.2 Function call [expr.call]

10 A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

11 If a function call is a prvalue of object type:

— if the function call is either — the operand of a decltype-specifier or — the right operand of a comma operator that is the operand of a decltype-specifier, a temporary object is not introduced for the prvalue. The type of the prvalue may be incomplete. [...]

— otherwise, the type of the prvalue shall be complete.

换句话说,你被允许的是用不完整的返回类型引入你的函数的提前声明。但是当你到达定义该函数或调用它,你应该有返回类型完成。