经过一些研究后,我发现如果前向声明可以,我应该尽量避免#include
我头文件中的内容。我如何转发声明std::size_t
?或者我必须在头文件中#include <cstddef>
吗?
文件 my_string.h :
#ifndef MY_STRING_H_
#define MY_STRING_H_
extern std::size_t;
namespace my
{
class string
{
public:
std::size_t length() const { return len; }
const char *c_str() const;
private:
std::size_t len;
}
}
#endif
文件 my_string.cpp :
#include "my_string.h"
#include <cstddef>
const char *my::string::c_str() const
{
for (std::size_t i = 0; i < len; ++i)
; // do stuff ...
return something;
}
显然这些例子并不完整......
我收到错误:error: 'size_t' in namespace 'std' does not name a type
(来自my_string.h
)。
编辑:感谢您的回答。我想我浪费时间试图强行不包括这个标题,但我只是想确保我没有错过一些简单的东西。
答案 0 :(得分:4)
extern
用于函数和变量,不用于类型别名。类型别名使用typedef
s。
如果你想为你自己的一个类型做这个,你可以从标题中复制它的typedef,并避免包含标题,但即使这样你也会得到重复的代码,这是一个维护责任。
size_t
的问题更严重:因为它背后的内置类型是系统相关的,所以你必须重现相同的逻辑或风险不兼容。与仅包含标题相比,这两个选项都非常糟糕。
答案 1 :(得分:4)
如果要开发库,则应避免在头文件中包含头文件,但始终需要在cpp文件中包含必需的头。 因此,最好只在cpp文件中包含特定的头文件,并在头文件中使用前向声明。 但是如果您的系统标题中存在依赖关系,那么您应该在头文件中包含该系统标题。
提示是包含标题的 源文件 (* .cpp,* .c)我们阻止最终用户解析我们开发的库的链接器依赖。
答案 2 :(得分:1)
size_t
是一个typedef,你不能用它来extern - extern用于变量或函数。
如果你确保在每一个之前就足够了:
#include "my_string.h"
有
#include <cstddef>
总是包括第一个编译器头(带有&lt;&gt;的onces),然后是本地头(带有“”的包含)的好习惯。
如果你需要一个类型定义为std :: size_t,那么即使在头文件中也要包含它。所有标题都应该有适当的包含防范以防止多个定义。保持只在.cpp文件中包含标题的习惯真的很难。编译器擅长优化多个头包含,Visual Studio提供预编译头,也是#pragma once
。
答案 3 :(得分:0)
不需要标头以特定顺序包括在内。这是一个完整的开发梦night,可能需要花很多时间才能使人们精通代码。最好确保标头在声明方面是“独立的”。
这需要在标头中包含或更好地包含任何依赖项:正向声明,以便可以完成所有声明而不会丢失任何内容。
如果使用前向声明,则CPP文件仍将需要包含额外的标头以完全定义所使用的数据类型,但是顺序不重要。
在原始问题中,my_string.h使用size_t作为成员变量,因此必须对其进行定义,而我宁愿包含所需的cstddef或stddef.h,也不希望my_string.h的用户使用首先包括它。在my_string.h的任何包含之前都要求包含这些标头之一并没有额外的好处,因为将完成相同数量的包含。
最后,由于size_t是typedef,因此从技术上来说,可以自己在my_string.h标头中对其进行typedef,因为在C ++中可以使用多个相同的typedef。但是,我建议不要这样做,因为size_t的大小取决于平台。