【基础实战01】C++基础之#pragma once的理解

  • 写于2024/08/03

    目录

    • [1. 什么是`#pragma once`](#pragma once`)
    • [2. 传统方法与`#pragma once`的使用示例对比](#pragma once`的使用示例对比)
    • [3. 传统方法与 `#pragma once` 的特点](#pragma once` 的特点)
      • [3.1 传统方法(包含保护宏)](#3.1 传统方法(包含保护宏))
      • [3.2 `#pragma once`](#pragma once`)
      • [3.3 对比总结](#3.3 对比总结)
    • [4. 代码实战](#4. 代码实战)

1. 什么是#pragma once

在C++中,#pragma once是用于防止头文件被多次包含的预处理指令,与传统的包含保护(#ifndef、#define、#endif)相比,它更加简洁高效。

2. 传统方法与#pragma once的使用示例对比

(1)传统方法:

cpp 复制代码
// Teacher.h
#ifndef TEACHER_H
#define TEACHER_H

#include "Student.h"

class Student;  // 前向声明

class Teacher {
public:
    void teach();
    Student* student;
};

#endif // TEACHER_H

在传统方法中,使用宏定义来防止头文件被多次包含。这个方法需要手动定义和检查宏,代码稍显繁琐。

(2)使用#pragma once:

cpp 复制代码
// Teacher.h
#pragma once
#include "Student.h"

class Student;  // 前向声明

class Teacher {
public:
    void teach();
    Student* student;
};

#pragma once通过编译器确保头文件只被编译一次,省去了宏定义和检查的步骤,更加简洁明了。

3. 传统方法与 #pragma once 的特点

3.1 传统方法(包含保护宏)

特点:

  1. 兼容性:

    • 使用条件编译指令 #ifndef、#define 和 #endif,几乎所有的C/C++编译器都支持。
    • 跨平台兼容,确保代码在不同编译器和操作系统上都能正常工作。
  2. 通用性:

    • 适用于所有C/C++项目,特别是需要跨平台兼容的项目。
  3. 模板:

    • 代码模板如下:

      cpp 复制代码
      #ifndef HEADER_NAME_H
      #define HEADER_NAME_H
      
      // 头文件内容:声明,定义语句...
      
      #endif // HEADER_NAME_H
  4. 维护成本:

    • 每个头文件需要定义唯一的宏名称,可能会增加维护成本,特别是在大型项目中。

3.2 #pragma once

特点:

  1. 简洁性:

    • 只需在头文件顶部添加 #pragma once,不需要定义和检查宏。
    • 代码更简洁,减少了潜在的错误。
  2. 性能:

    • 编译器可以更高效地处理头文件,减少重复编译的开销。
  3. 支持情况:

    • 大多数现代编译器(如GCC、Clang、MSVC)都支持。
    • 某些老旧或特殊编译器可能不支持。
  4. 模板:

    • 代码模板如下:

      cpp 复制代码
      #pragma once
      
      // 头文件内容

3.3 对比总结

  • 兼容性 :传统方法在任何编译器上都能工作,而 #pragma once 依赖于编译器的支持。
  • 简洁性 :#pragma once 更加简洁,减少了代码量和出错的可能性。
  • 维护成本 :#pragma once 维护成本较低,不需要管理多个宏名称。
  • 性能 :#pragma once 可能具有更好的编译性能,因为编译器可以优化处理。

在现代开发环境中,#pragma once 通常是首选方法,但在需要跨平台兼容的项目中,传统方法仍然是一个可靠的选择。

4. 代码实战

在使用VS2022创建头文件时,大家会发现,VS2022会默认在新建的头文件中的第一行生成#pragma once

(1)使用 #pragma once 的示例

以下是一个简单的C++项目示例,展示如何使用 #pragma once 来防止头文件的重复包含。

文件结构

复制代码
project/
│
├── main.cpp
├── Teacher.h
└── Student.h

头文件 Teacher.h

cpp 复制代码
// Teacher.h
#pragma once
#include "Student.h"

class Student;  // 前向声明

class Teacher {
public:
    void teach();
    Student* student;
};

头文件 Student.h

cpp 复制代码
// Student.h
#pragma once
#include "Teacher.h"

class Teacher;  // 前向声明

class Student {
public:
    void study();
    Teacher* teacher;
};

源文件 main.cpp

cpp 复制代码
// main.cpp
#include <iostream>
#include "Teacher.h"
#include "Student.h"

void Teacher::teach() {
    std::cout << "Teaching a student." << std::endl;
}

void Student::study() {
    std::cout << "Studying with a teacher." << std::endl;
}

int main() {
    Teacher teacher;
    Student student;

    teacher.student = &student;
    student.teacher = &teacher;

    teacher.teach();
    student.study();

    return 0;
}

详细解释

  1. 文件结构 :
    • main.cpp 是程序的入口点。
    • Teacher.h 和 Student.h 是两个头文件,分别定义了 Teacher 和 Student 类。
  2. 前向声明 :
    • 在 Teacher.h 和 Student.h 中,都有对另一个类的前向声明,避免了循环依赖的问题。
  3. #pragma once :
    • 每个头文件顶部使用 #pragma once,确保头文件只被编译一次,防止重复包含。

(2)使用传统方法防止头文件重复包含的示例

文件结构

复制代码
project/
│
├── main.cpp
├── Teacher.h
└── Student.h

头文件 Teacher.h

cpp 复制代码
// Teacher.h
#ifndef TEACHER_H
#define TEACHER_H

#include "Student.h"

class Student;  // 前向声明

class Teacher {
public:
    void teach();
    Student* student;
};

#endif // TEACHER_H

头文件 Student.h

cpp 复制代码
// Student.h
#ifndef STUDENT_H
#define STUDENT_H

#include "Teacher.h"

class Teacher;  // 前向声明

class Student {
public:
    void study();
    Teacher* teacher;
};

#endif // STUDENT_H

源文件 main.cpp

cpp 复制代码
// main.cpp
#include <iostream>
#include "Teacher.h"
#include "Student.h"

void Teacher::teach() {
    std::cout << "Teaching a student." << std::endl;
}

void Student::study() {
    std::cout << "Studying with a teacher." << std::endl;
}

int main() {
    Teacher teacher;
    Student student;

    teacher.student = &student;
    student.teacher = &teacher;

    teacher.teach();
    student.study();

    return 0;
}

详细解释

  1. 文件结构 :
    • main.cpp 是程序的入口点。
    • Teacher.h 和 Student.h 是两个头文件,分别定义了 Teacher 和 Student 类。
  2. 前向声明 :
    • 在 Teacher.h 和 Student.h 中,都有对另一个类的前向声明,避免了循环依赖的问题。
  3. 包含保护 :
    • 每个头文件顶部使用 #ifndef、#define 和 #endif,确保头文件只被编译一次,防止重复包含。

写在最后

通过本篇博客,我们探讨了C++中#pragma once与传统包含保护方法的使用和特点。#pragma once提供了更为简洁和高效的方式来防止头文件的重复包含,而传统方法则具有更广泛的兼容性和通用性。

在实际项目中,选择哪种方法取决于项目的需求和目标编译器的支持情况。在现代开发环境中,#pragma once通常是首选方法,但在需要跨平台兼容的项目中,传统方法仍然是一个可靠的选择。

学习编程不仅仅是掌握语法和使用工具,更重要的是理解背后的思想和原理。希望通过我的博客,能够帮助你更好地理解和应用这些技术,不断提升自己的编程能力。在实际项目中多实践、多思考,将理论与实践相结合,才能真正掌握这些编程技巧。祝你在编程的道路上不断进步!


转载请标明出处

如果还有问题,欢迎在评论区留言或私信

作者:CodeLearing

主页:https://blog.csdn.net/weixin_52677672?type=blog

QQ群:958124241

Learn Together!

相关推荐
泡泡糖的中文规格书13 分钟前
HDLbits 2.2 学习笔记 · 多路复用器
java·开发语言
John_Hui16 分钟前
第 3 篇:配置 JDK 17 环境
java·开发语言·ubuntu
鶴哥只手遮天25 分钟前
AFSIM 2.9.0 深度解析:架构、原理与工程实践-第 1 章 项目全景与代码地图
c++
充值内卷30 分钟前
C++单文件迷宫游戏:TauriCPP 开发全记录
开发语言·c++·游戏
Antruly31 分钟前
C++ Web 开发选型漫谈:从 Drogon 到 libuvcpp + uvp,八个项目的定位、兼容性与务实排名
开发语言·前端·c++
EnCi Zheng35 分钟前
AI Agent工具调用防护层怎么写-一份能直接跑的Python四层拦截实现
大数据·开发语言·python
香蕉大香蕉(06敬畏市场)1 小时前
高频八股 · Java 并发编程(10):异步、ThreadLocal 与虚拟线程(收官)
java·开发语言·网络·jvm·python·ai·实习
念何架构之路1 小时前
Go reflect包值操作 Value 的读写、可设置性与 interface 布局
开发语言·后端·golang
云中飞鸿1 小时前
.Net和C#有什么关系?(从C++视角观察)
开发语言·c#·.net
another heaven1 小时前
【C/C++ C++ 新特性中的那些内存优化的特性】
c语言·开发语言·c++