在标题

时间:2016-05-11 09:47:59

标签: c++

经过一些研究后,我发现如果前向声明可以,我应该尽量避免#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)。

编辑:感谢您的回答。我想我浪费时间试图强行不包括这个标题,但我只是想确保我没有错过一些简单的东西。

4 个答案:

答案 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的大小取决于平台。