C++:头文件

简介

必须声明变量、函数、类等程序元素的名称,然后才能使用这些元素。 例如,不能仅在 x = 42 不首先声明 “x” 的情况下编写。

int x; // declaration
x = 42; // use x

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

为了最大限度地减少可能出现的错误,c + + 采用了使用 头文件 来包含声明的约定。 在标头文件中创建声明,然后在每个 .cpp 文件或需要该声明的其他头文件中使用 #include 指令。 在编译之前,#include 指令会将标头文件的副本直接插入到 .cpp 文件中。

备注

在 Visual Studio 2019 中,c + + 20 模块 功能被引入为标头文件的改进和最终替换。

示例

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

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

}

接下来,创建一个 (通常使用 .cpp 或类似扩展名) 的实现文件。 我们将调用文件 my_class .cpp 并为成员声明提供定义。 我们 #include 为 “my_class .h” 文件添加了指令,以便在此点处插入 my_class 声明,并在的声明中加入 std::cout 。 请注意,引号用于与源文件位于同一目录中的头文件,而尖括号用于标准库标头。 而且,许多标准库标头不包含 .h 或任何其他文件扩展名。

在实现文件中,可以选择性地使用 using 语句,以避免使用 “N::” 或 “std::” 对 “my_class” 或 “cout” 的每个提到。 不要 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;
}

现在,我们可以 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;
}

在编译器将每个 .cpp 文件编译为 .obj 文件后,它会将 .obj 文件传递到链接器。 当链接器合并对象文件时,它只查找 my_class 的一个定义;它位于为 my_class 生成的 .obj 文件中,并且生成成功。

Include 临界

通常情况下,头文件具有 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 */

要放置在标头文件中的内容

因为标头文件可能由多个文件包含,所以它不能包含可能产生同一名称的多个定义的定义。 不允许执行以下操作,或将其视为非常糟糕的做法:

命名空间或全局范围内的内置类型定义
非内联函数定义
非常量变量定义
聚合定义
未命名的命名空间
using 指令
使用 using 指令不一定会导致错误,但可能会导致出现问题,因为它会将命名空间引入到直接或间接包含该标头的每个 .cpp 文件的范围中。

示例标头文件

下面的示例演示了标头文件中允许的各种声明和定义:

// 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;
}

该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处
本文章博客地址:https://blog.youkuaiyun.com/it_cplusplus/article/details/118107325

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值