如果我将代码拆分为 .h 和 .cpp 文件,则标头中使用的以下关键字中哪些也必须在 .cpp 文件中使用,并且不得进入 .cpp 文件中:
const, virtual, override, noexcept, constexpr
以及必须按什么顺序使用它们,即以下顺序是否正确:
virtual constexpr int foo() const override noexcept;
如果存在这样的规则,请随意给出。
7
2 个回答
2
“虚拟”说明符是类定义的一部分,并且仅属于类成员规范,在本例中是非静态类成员函数的声明(带或不带定义)。 “虚拟”成员是类的属性,而不是函数类型的属性。
“限定符”(const、易失性、、&
)&&
和constexpr
/consteval
说明符是函数的一部分,因此必须出现在(成员)函数的每个声明中(包括定义函数,无论是内联函数还是外联函数) :
// Class definition of X; specifies the members of X.
struct X : Base {
virtual void f() const; // virtual and override
void g() && override; // are part of "being a member"
};
// Function declarations and definitions:
// qualifiers are part of the function.
void X::f() const { /* ... */ }
void X::g() && { /* ... */ }
这与 .h 和 .cpp 文件本身无关,尽管人们通常会将外联定义放入 .cpp 文件中。 (如果将其保留在标头中,则当标头包含在不同的翻译单元中时,会导致重复定义,除非其中一个声明也显式指定为inline
。相比之下,类成员函数的内联定义是隐式的inline
。)
4
-
非常感谢!
– -
很好的答案,感谢您向我指出裁判资格。直到!
– -
这份清单相当不完整。
noexcept
– 声明和定义之间的规范、语言链接、约束等也需要匹配。或者我猜一般来说,任何属于函数签名一部分的东西。
–
-
@JanSchultke是的,确实如此 – 这就是为什么我试图指出“类成员”和“函数类型”之间的根本区别。随着 C++ 的发展,细节肯定会发生变化。感谢您的补充。
–
|
简而言之,您需要重复属于其类型一部分的函数部分和/或使两个函数对应所必需的部分。因此,您需要重复:
- 函数参数和返回类型
const
和volatile
预选赛- ref 限定符 (
&
和&&
) requires
条款noexcept
规格
通常,为了使标头中的函数声明与源文件中的定义匹配,这些声明需要。对于函数,这意味着它们需要(请参阅):
两个函数或函数模板声明声明,如果:
- 声明函数,等效 ([temp.over.link]) 尾随的require-clause s(如果有,除非 [temp.friend] 中指定),并且,如果两者都是非静态成员,它们有,或者
- 两者都声明具有相应签名和等效模板头以及尾随需求子句(如果有)的函数模板。
让我们只关注第一个项目符号,因为您不是在询问模板。首先,参数列表需要相同(不包括显式对象参数,即this auto
和其他形式)。其次,对象参数需要相同,即const
、volatile
、&
、&&
必须匹配。第三,该requires
条款需要等效。
noexcept
规格也需要相同,因为noexcept
适用于功能类型。不能有两个不同类型的对应声明:
int x(int);
int x(float); // OK, x(float) does not correspond to x(int) and is a separate overload
int x(int) noexcept; // error: x(int) declared with two different types
其他所有内容(例如属性virtual
等)都适用于声明,并且不必在定义中重复。
|
constexpression
不是关键字 – 您可能是指constexpr
, whileoverride
不是关键字。无论如何,(1) 按照惯例,.cpp 文件#include
头文件,并且头文件可以(可选)#include
彼此,并且 (2) 的效果#include
是执行文本替换并将#include
指令的内容替换为指定文件的内容。因此,出现在标头中的任何构造(包括任何关键字)都可以出现在源文件中,反之亦然。–
–
–
–
virtual
在所有虚拟函数上都有一个。即使不需要时。–
|