编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

C++|头文件应该包含什么,不应该包含什么

gowuye 2024-04-25 04:46 12 浏览 0 评论

0 declaration and definition

The names of program elements such as variables, functions, classes, and so on must be declared before they can be used. For example, you can't just write x = 42 without first declaring 'x'.

在使用程序元素(如变量、函数、类等)之前,必须声明它们的名称。例如,如果不先声明“x”,就不能只写x=42。

int x;      // declaration,not a pure declaration, also a definition
x = 42;  // use x

The declaration tells the compiler whether the element is an int, a double, a function, a class or some other thing. Furthermore, each name must be declared (directly or indirectly) in every .cpp file in which it is used. When you compile a program, each .cpp file is compiled independently into a compilation unit. The compiler has no knowledge of what names are declared in other compilation units. That means that if you define a class or function or global variable, you must provide a declaration of that thing in each additional .cpp file that uses it. Each declaration of that thing must be exactly identical in all files. A slight inconsistency will cause errors, or unintended behavior, when the linker attempts to merge all the compilation units into a single program.

声明告诉编译器元素是int、double、函数、类还是其他东西。此外,每个名称必须(直接或间接)在每个使用这个名称的.cpp文件中声明。编译程序时,每个.cpp文件独立编译成一个编译单元。编译器不知道在其他编译单元中声明了什么名称。这意味着,如果定义一个类、函数或全局变量,则必须在每个附加的.cpp文件中提供使用这些东西的声明。该事物的每个声明在所有文件中都必须完全相同。当链接器尝试将所有编译单元合并到单个程序中时,轻微的不一致将导致错误或意外行为。

To minimize the potential for errors, C++ has adopted the convention of using header files to contain declarations. You make the declarations in a header file, then use the #include directive in every .cpp file or other header file that requires that declaration. The #include directive inserts a copy of the header file directly into the .cpp file prior to compilation.

为了尽量减少错误的可能性,C++采用了使用头文件包含声明的约定。在头文件中进行声明,然后在每个 ,cpp文件或其他需要该声明的头文件中使用#include指令。#include指令将头文件的副本直接插入到编译前的cpp文件。

The C++20 modules feature is introduced as an improvement and eventual replacement for header files.

C++20引入模块功能是为了改进并最终替换头文件。

A C++ program consists of various entities such as variables, functions, types, and namespaces. Each of these entities must be declared before they can be used. A declaration specifies a unique name for the entity, along with information about its type and other characteristics. In C++ the point at which a name is declared is the point at which it becomes visible to the compiler. You can't refer to a function or class that is declared at some later point in the compilation unit. Variables should be declared as close as possible before the point at which they're used.

C++程序由各种实体组成,如变量、函数、类型和名称空间。在使用这些实体之前,必须声明它们中的每一个。声明指定实体的唯一名称,以及有关其类型和其他特征的信息。在C++中,声明名称的点是编译器可以看到名称的点。您不能引用编译单元中稍后某个点声明的函数或类。变量应在使用点之前声明为尽可能接近。

Some entities, including functions, classes, enums, and constant variables, must be defined as well as declared. A definition provides the compiler with all the information it needs to generate machine code when the entity is used later in the program. A constant variable must be defined, in other words assigned a value, in the same statement in which it's declared. A declaration of a built-in type such as int is automatically a definition because the compiler knows how much space to allocate for it.

一些实体,包括函数、类、枚举和常量变量,必须定义和声明。定义为编译器提供了在程序稍后使用实体时生成机器代码所需的所有信息。常量变量必须在声明它的同一语句中定义,换句话说,指定一个值。内置类型(如int)的声明自动成为定义,因为编译器知道要为其分配多少空间。

1 Translation units and linkage

In a C++ program, a symbol, for example a variable or function name, can be declared any number of times within its scope. However, it can only be defined once. This rule is the "One Definition Rule" (ODR). A declaration introduces (or reintroduces) a name into the program, along with enough information to later associate the name with a definition. A definition introduces a name and provides all the information needed to create it. If the name represents a variable, a definition explicitly creates storage and initializes it. A function definition consists of the signature plus the function body. A class definition consists of the class name followed by a block that lists all the class members. (The bodies of member functions may optionally be defined separately in another file.)

在C++程序中,可以在其作用域内多次声明符号,例如变量或函数名。然而,它只能定义一次。该规则是“一次定义规则”(ODR)。声明在程序中引入(或重新引入)名称,以及足够的信息,以便稍后将名称与定义相关联。定义引入名称并提供创建名称所需的所有信息。如果名称表示变量,则定义会显式创建存储并对其进行初始化。函数定义由签名和函数体组成。类定义由类名后跟列出所有类成员的块组成。(可以选择在另一个文件中单独定义成员函数体。)

The following example shows some declarations:

以下示例显示了一些声明:

int i;  // variable declaration, not pure, also definition
extern int j; // pure variable declaration
int f(int x); // function declaration
class C; // class declaration

The following example shows some definitions:

以下示例显示了一些定义:

int i{42};   // variable definition, and initialize
int f(int x){ return x * i; } // function definition
class C { // class definition
public:
   void DoSomething();
};

A program consists of one or more translation units. A translation unit consists of an implementation file and all the headers that it includes directly or indirectly. Implementation files typically have a file extension of .cpp or .cxx. Header files typically have an extension of .h or .hpp. Each translation unit is compiled independently by the compiler. After the compilation is complete, the linker merges the compiled translation units into a single program. Violations of the ODR rule typically show up as linker errors. Linker errors occur when the same name is defined in more than one translation unit.

程序由一个或多个翻译单元组成。翻译单元由一个实现文件和它直接或间接包含的所有头文件组成。实现文件的文件扩展名通常为.cpp或.cxx。头文件的扩展名通常为.h或.hpp。每个翻译单元由编译器独立编译。编译完成后,链接器将编译后的翻译单元合并到单个程序中。违反ODR规则通常表现为链接器错误。当在多个翻译单元中定义相同名称时,会发生链接器错误。(编译阶段对标识符做声明查找,链接阶段做定义匹配。)

In general, the best way to make a variable visible across multiple files is to declare it in a header file. Then add an #include directive in every .cpp file that requires the declaration. By adding include guards around the header contents, you ensure that the names a header declares are only declared once for each translation unit. Define the name in only one implementation file.

通常,使变量在多个文件中可见的最佳方法是在头文件中声明它。然后在每个需要声明的.cpp文件中添加一个#include指令。通过在添加include-guard,可以确保头文件中声明的名称对于每个翻译单元只声明一次。仅在一个实现文件中定义名称。

In C++20, modules are introduced as an improved alternative to header files.

在C++20中,引入模块作为头文件的改进替代方案。

In some cases, it may be necessary to declare a global variable or class in a .cpp file. In those cases, you need a way to tell the compiler and linker what kind of linkage the name has. The type of linkage specifies whether the name of the object is visible only in one file, or in all files. The concept of linkage applies only to global names. The concept of linkage doesn't apply to names that are declared within a scope. A scope is specified by a set of enclosing braces such as in function or class definitions.

在某些情况下,可能需要在cpp文件中声明全局变量或类。在这种情况下,您需要一种方法来告诉编译器和链接器名称具有何种链接。链接类型指定对象的名称是仅在一个文件中可见,还是在所有文件中可见。链接的概念仅适用于全局名称。链接的概念不适用于在作用域内声明的名称。作用域由一组括号指定,例如在函数或类定义中。

2 using a head file and source file to defina and use a class

The following example shows a common way to define a class and then use it in a different source file. We'll start with the header file, my_class.h. It contains a class definition, but note that the definition is incomplete; the member function do_something is not defined:

下面的示例显示了一种常见的方法,可以定义一个类,然后在不同的源文件中使用它。我们将从头文件my_class.h开始。它包含一个类定义,但请注意,该定义不完整,未定义成员函数do_something():

// my_class.h
namespace N
{
    class my_class
    {
    public:
        void do_something();
    };
}

Next, create an implementation file (typically with a .cpp or similar extension). We'll call the file my_class.cpp and provide a definition for the member declaration. We add an #include directive for "my_class.h" file in order to have the my_class declaration inserted at this point in the .cpp file, and we include <iostream> to pull in the declaration for std::cout. Note that quotes are used for header files in the same directory as the source file, and angle brackets are used for standard library headers. Also, many standard library headers do not have .h or any other file extension.

接下来,创建一个实现文件(通常具有.cpp或类似扩展名)。我们将该文件称为my_class.cpp并为成员声明提供定义。我们为“my_class.h”文件添加了一个#include指令,以便在.cpp文件中插入my_class声明(特别是有多个成员函数或自由函数需要实现且存在相互调用关系时)。并且我们包括<iostream>来拉入std::cout的声明。请注意,引号用于源文件所在目录中的头文件,尖括号用于标准库头文件。此外,许多标准库标头没有.h或任何其他文件扩展名。

In the implementation file, we can optionally use a using statement to avoid having to qualify every mention of "my_class" or "cout" with "N::" or "std::". Don't put using statements in your header files!

在实现文件中,我们可以选择使用using语句,以避免每次提到“my_class”或“cout”时都必须用“N::”或“std::”限定。不要把using语句放在头文件中!

// my_class.cpp
#include "my_class.h" // header in local directory
#include <iostream> // header in standard library

using namespace N;
using namespace std;

void my_class::do_something()
{
    cout << "Doing something!" << endl;
}

Now we can use my_class in another .cpp file. We #include the header file so that the compiler pulls in the declaration. All the compiler needs to know is that my_class is a class that has a public member function called do_something().

现在我们可以在另一个.cpp文件中使用my_class.cpp文件。我们#include头文件,以便编译器拉入声明。编译器需要知道的是,my_class是一个具有公共成员函数do_something()的类。

// my_program.cpp
#include "my_class.h"

using namespace N;

int main()
{
    my_class mc;
    mc.do_something();
    return 0;
}

After the compiler finishes compiling each .cpp file into .obj files, it passes the .obj files to the linker. When the linker merges the object files it finds exactly one definition for my_class; it is in the .obj file produced for my_class.cpp, and the build succeeds.

在编译器编译完每个.cpp文件为.obj文件后,编译器传递.obj文件给链接器。当链接器合并.obj文件时,它正好找到my_class的一个定义;在.obj文件内为my_class.cpp生成的obj文件.cpp,构建成功。

3 Include guards

Typically, header files have an include guard or a #pragma once directive to ensure that they are not inserted multiple times into a single .cpp file.

通常,头文件具有include-guard或#pragma-once指令,以确保它们不会多次插入到单个文件中.cpp文件。

// my_class.h
#ifndef MY_CLASS_H // include guard
#define MY_CLASS_H

namespace N
{
    class my_class
    {
    public:
        void do_something();
    };
}

#endif /* MY_CLASS_H */

4 What not to put in a header file

Because a header file might potentially be included by multiple files, it cannot contain definitions that might produce multiple definitions of the same name. The following are not allowed, or are considered very bad practice:

由于头文件可能包含在多个文件中,因此它不能包含可能产生相同名称的多个定义的定义。以下是不允许的,或被视为非常糟糕的做法:

built-in type definitions at namespace or global scope

命名空间或全局范围中的内置类型定义

non-inline function definitions

非内联函数定义

non-const variable definitions

非常量变量定义

aggregate definitions

聚合定义

unnamed namespaces

未命名命名空间

using directives

using指令

Use of the using directive will not necessarily cause an error, but can potentially cause a problem because it brings the namespace into scope in every .cpp file that directly or indirectly includes that header.

使用using指令不一定会导致错误,但可能会导致问题,因为它会将命名空间引入到每个直接或间接包含该头文件的cpp文件中的作用域中。

5 Internal linkage by default

A free function is a function that is defined at global or namespace scope. Non-const global variables and free functions by default have external linkage; they're visible from any translation unit in the program. No other global object can have that name. A symbol with internal linkage or no linkage is visible only within the translation unit in which it's declared. When a name has internal linkage, the same name may exist in another translation unit. Variables declared within class definitions or function bodies have no linkage.

自由函数是在全局或命名空间范围内定义的函数。默认情况下,非常量全局变量和自由函数具有外部链接;它们可以从程序中的任何翻译单元中看到。没有其他全局对象可以具有该名称。具有内部链接或无链接的符号仅在其声明的翻译单元内可见。当一个名称具有内部链接时,同一名称可能存在于另一个翻译单元中。在类定义或函数体中声明的变量没有链接。

You can force a global name to have internal linkage by explicitly declaring it as static. This keyword limits its visibility to the same translation unit in which it's declared. In this context, static means something different than when applied to local variables.

通过显式地将全局名称声明为静态,可以强制全局名称具有内部链接。该关键字将其可见性限制在声明它的同一翻译单元。在这种情况下,静态的含义与应用于局部变量时不同。

The following objects have internal linkage by default:

默认情况下,以下对象具有内部链接:

const objects

常量对象

constexpr objects

constexpr对象

typedef objects

typedef对象

static objects in namespace scope

命名空间范围中的静态对象

To give a const object external linkage, declare it as extern and assign it a value:

要赋予常量对象外部链接,请将其声明为extern并为其赋值:

extern const int value = 42;

6 What to put in a header file

The various kinds of declarations and definitions that are allowed in a header file:

头文件中允许的各种声明和定义:

命名空间

enum定义

const常量定义(默认为内部链接)

constexpr定义

类型别名定义

extern声明

条件编译指令

全局函数声明

宏定义

类定义

结构体定义

类模板定义及类模板成员函数实现

类模板声明

The following example shows the various kinds of declarations and definitions that are allowed in a header file:

以下示例显示了头文件中允许的各种声明和定义:

// sample.h
#pragma once
#include <vector> // #include directive
#include <string>

namespace N  // namespace declaration
{
    inline namespace P
    {
        //...
    }

    enum class colors : short { red, blue, purple, azure };

    const double PI = 3.14;  // const and constexpr definitions
    constexpr int MeaningOfLife{ 42 };
    constexpr int get_meaning()
    {
        static_assert(MeaningOfLife == 42, "unexpected!"); // static_assert
        return MeaningOfLife;
    }
    using vstr = std::vector<int>;  // type alias
    extern double d; // extern variable

#define LOG   // macro definition

#ifdef LOG   // conditional compilation directive
    void print_to_log();
#endif

    class my_class   // regular class definition,
    {                // but no non-inline function definitions

        friend class other_class;
    public:
        void do_something();   // definition in my_class.cpp
        inline void put_value(int i) { vals.push_back(i); } // inline OK

    private:
        vstr vals;
        int i;
    };

    struct RGB
    {
        short r{ 0 };  // member initialization
        short g{ 0 };
        short b{ 0 };
    };

    template <typename T>  // template definition
    class value_store
    {
    public:
        value_store<T>() = default;
        void write_value(T val)
        {
            //... function definition OK in template
        }
    private:
        std::vector<T> vals;
    };

    template <typename T>  // template declaration
    class value_widget;
}

ref

https://docs.microsoft.com/en-us/cpp/cpp/declarations-and-definitions-cpp

https://docs.microsoft.com/en-us/cpp/cpp/program-and-linkage-cpp

https://docs.microsoft.com/en-us/cpp/cpp/header-files-cpp

-End-

相关推荐

Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优
Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优

Nginx缓存优化是帮助大家提升网站性能的重要操作之一,proxy_cache主要用于反向代理时,对后端内容源服务器进行缓存;fastcgi_cache主要用于...

2024-05-20 14:44 gowuye

王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动
王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动

王者荣耀官方终于确定了天魔缭乱和逐梦之音的返场活动,这让不少小伙伴乐开了花,返场活动将会在3月22日开启,下面就带来王者荣耀天魔缭乱和逐梦之音返场活动地址!王者...

2024-05-20 14:44 gowuye

常见的嵌入式web服务器有哪些?

嵌入式WEB服务器常见的有:Lighttpd,Shttpd,Thttpd,Boa,Mini_httpd,Appweb,Goahead。Lighttpd地址:http://www.light...

简述几款常见的嵌入式web服务器
简述几款常见的嵌入式web服务器

嵌入式web服务器,是web服务器当中的一种,是基于嵌入式系统而实现的web服务器。指的是在嵌入式系统(通俗点就是单片机系统)上实现的一个web服务器,可以通过...

2024-05-20 14:44 gowuye

教你如何利用fastcgi_cache缓存加速WordPress

在使用nginx缓存之前,必须在nginx里面加载专门的模块,这个模块叫做ngx_cache_purge。添加ngx_cache_purge模块下载ngx_cache_purge模块ngx_cache...

扫描WordPress漏洞

检测已知漏洞WPScan是一款广泛使用的WordPress安全扫描工具,它的一项重要功能是检测已知漏洞。在这篇文章中,我们将深入探讨WPScan如何检测已知漏洞,并结合实际示例,帮助读者更好地理解和应...

消灭 Bug!推荐几个给力的开源 Bug 跟踪工具
消灭 Bug!推荐几个给力的开源 Bug 跟踪工具

在这个充满bug的世界里,最遥远的距离不是生与死,而是你亲手制造的bug就在你眼前,你却怎么都找不到它。因此本文准备了7款优秀的开源bug跟踪系...

2024-05-20 14:43 gowuye

生物信息分析入门全攻略

生物信息学是生命科学研究的重大前沿领域,未来将占据生命科学研究的半壁江山。已经有越来越多的小伙伴投入到生物信息的学习中,但是入门难、深入慢、摸不到方向等都成为持续学习的拦路虎。本文根据生物信息技术大牛...

elkb实践经验,再赠送一套复杂的配置文件
elkb实践经验,再赠送一套复杂的配置文件

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。宝剑锋从磨砺出,梅花香自苦寒来。诗人白居易,三月下江南,看到沿路开放的桃花,心潮澎湃...

2024-05-20 14:43 gowuye

超详细从0到1 搭建ELK监控
超详细从0到1 搭建ELK监控

监控分类?Metrics用于记录可聚合的数据。例如,1、队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新;HTTP请求个数可被定义为一个计数器,...

2024-05-20 14:42 gowuye

嵌入式开发 之Web配置页面开发
嵌入式开发 之Web配置页面开发

1.PHP是最好的语言??开发动态页面首选的语言是PHP,村村不能在这里忽悠人,如果你的硬件性能允许切略懂PHP,看到这里就可以退出了。本文面向的受众是Linu...

2024-05-20 14:42 gowuye

Python开发一个网站目录扫描工具用来检测网站是否有漏洞?
Python开发一个网站目录扫描工具用来检测网站是否有漏洞?

开发一个网站目录扫描工具是用来检测网站是否有非法目录请求的一个常见需求之一,我们要通过这个扫描工具来找到通过某个域名可以访问到的网站路径,可能对于有些系统来讲,...

2024-05-20 14:42 gowuye

创建一个类似Youtube的Id——使用PHP/Python/JS/Java/SQL

id通常都是用数字,不巧的是只有10个数字来使用,所以如果你有很多的记录,id往往变得非常冗长。当然对于计算机来说无所谓,但我们更希望id尽可能短。所以我们如何能使id变短?我们可以利用字母让它们附加...

快速云:有助于移动应用安全开发的五条妙计
快速云:有助于移动应用安全开发的五条妙计

许多企业不断地向其开发团队提供培训。但是某些漏洞,如早在十多年前就发现的SQL注入,如今仍广泛存在于各种应用中。因而,安全培训永不过时。在开发移动应用时,开发者...

2024-05-20 14:41 gowuye

洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映
洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映

7月2日,由M&CSaatchi创作,由深受好评的澳大利亚导演迈克尔·格雷西执导的动画短片《G’day》,正式在全网上映。该影片因其出色的创意赢得了洛...

2024-05-20 14:41 gowuye

取消回复欢迎 发表评论: