侯捷 C++ 课程学习笔记:头文件与类的声明
目录
本篇相对实操性较强,所以需要编写简单的程序,包含不同类型的头文件引用和类的声明,逐渐增加复杂度,深入理解其用法。对自己编写的代码以及优秀的开源代码进行分析,学习其中头文件和类声明的规范和技巧。
这里侯老师对C与C++的头部写法还做了一个对比。
头文件概念与作用说明
头文件用于存储预定义的函数、类、结构体等,可提高代码的重用性和可读性。其扩展名不一定是.h,如<iostream>就没有传统的.h 扩展名。
- 常见头文件:<iostream>用于输入输出操作,<cmath>提供数学函数,<vector>支持动态数组等。了解这些头文件及其提供的功能很重要。
- 防卫式声明:也叫头文件保护或头文件宏定义,是防止头文件被多次包含的技术,利用条件编译指令实现。例如:
#ifndef FILENAME_H #define FILENAME_H // 头文件内容 #endif
其中FILENAME_H是自定义宏,当第一次包含该头文件时,宏未定义,头文件内容被包含,后续再包含时,宏已定义,内容不再重复包含,避免多重定义错误。
C++头文件与库的说明
定义与作用
库是预先编译好的代码集合,它包含了一系列的函数、类、对象等,可供其他程序调用。使用库可以避免重复编写代码,提高开发效率,同时也有助于代码的模块化和管理。
常见类型
- 标准库:C++ 标准库是 C++ 语言的一部分,它提供了丰富的功能,包括输入输出、容器、算法、字符串处理等。标准库分为两部分:C++ 标准模板库(STL)和标准库的其他部分。STL 包含了容器(如 vector、list、map)、迭代器、算法等;其他部分则包含了如 <iostream> 等用于输入输出的功能。
- 第三方库:由第三方开发者或组织开发的库,用于提供特定的功能。例如,Boost 库是一个广泛使用的第三方 C++ 库,提供了许多高级功能,如智能指针、正则表达式、多线程等;OpenCV 是用于计算机视觉的库,提供了图像和视频处理的功能。
- 自定义库:开发者根据自己的项目需求创建的库。比如,在一个大型项目中,可以将一些通用的功能封装成一个库,供项目中的其他模块使用。
静态库与动态库
- 静态库:扩展名为 .lib(Windows)或 .a(Linux)。在编译时,静态库的代码会被完整地复制到可执行文件中。这样,可执行文件在运行时不需要依赖外部的库文件,但会导致可执行文件体积增大。
- 动态库:扩展名为 .dll(Windows)或 .so(Linux)。动态库的代码在运行时才会被加载到内存中。可执行文件只包含对动态库中函数和变量的引用,因此可执行文件体积较小,而且多个程序可以共享同一个动态库,节省内存资源。
库的使用
要使用一个库,通常需要完成以下步骤:
- 包含头文件:在源文件中包含库提供的头文件,以获取库中函数和类的声明。
- 链接库文件:在编译时,告诉编译器链接相应的库文件。对于静态库,编译器会将库的代码链接到可执行文件中;对于动态库,编译器会生成可执行文件对动态库的引用。例如,在使用 g++ 编译器时,可以使用 -l 选项来指定要链接的库,如 -l boost_system 表示链接 Boost 库中的 system 模块。
C语言头部分件 VS C++头部文件
对比维度 | C 语言头部文件 | C++ 头部文件 |
---|---|---|
后缀与形式 | 传统后缀为 .h,如 stdio.h、math.h | 除兼容 .h 后缀外,有不带 .h 后缀的,如 <iostream>、<vector>;还有 .hpp 后缀,用于类和模板定义 |
包含内容 | 结构体、联合体、枚举类型声明,类型定义,宏定义,函数声明 | 除 C 语言头部文件内容外,有类声明、成员函数声明、模板定义等,支持面向对象编程 |
编译处理方式 | 预处理阶段直接包含进源文件,按 C 语言规则编译处理函数声明 | 因支持函数重载,处理较复杂;为实现 C 和 C++ 代码混合编译,常用 extern "C" 声明 |
头文件数量与功能侧重 | 数量较少,侧重基本输入输出、数学运算、字符串处理等底层功能 | 数量丰富,除 C 语言功能外,涵盖面向对象编程、容器算法、输入输出流等高级功能 |
有了表就很直接了,方便做对照。
类的声明
基本概念:
- 类是用户自定义的数据类型,包含属性(数据成员)和行为(成员函数)。例如,定义一个简单的
Person
类:#include <string> // 头部文件引入string class Person { public: // 成员函数 void setName(const std::string& name) { this->name = name; } std::string getName() const { return name; } private: // 数据成员 std::string name; };
访问权限:
- public(公共)权限的成员在类内外都可访问;private(私有)权限的成员只能在类内部访问;protected(保护)权限与private类似,但派生类可以访问。
构造函数:
- 名称与类名相同,无返回值,用于对象的初始化。例如:
-
class Complex { public: // 构造函数,初始化复数的实部和虚部 Complex(double r = 0, double i = 0) : re(r), im(i) {} private: double re, im; };
成员函数:
- 分为在类体内直接定义(隐式内联)和在类体外定义两种方式。在类体外定义时,需要使用类名和作用域解析运算符
::
,如:class Complex { public: Complex& operator+=(const Complex&); }; // 重载加法赋值运算符,用于将一个复数加到当前复数上 Complex& Complex::operator+=(const Complex& rhs) { // 函数体 return *this; }
友元:
- 允许非成员函数或其他类访问本类的私有和保护成员。声明友元函数使用friend关键字,如:
// 定义一个名为Complex的类,用于表示复数 class Complex { // 声明一个友元函数operator+,用于实现复数的加法运算 friend Complex operator+(const Complex&, const Complex&); };
头部文件与类的声明总结
在 C++ 中,头文件与类的声明是构建程序的重要基础。头文件常以.h或.hpp为扩展名,用于存放函数、类的声明,宏定义等内容。它能避免代码重复编写,提高可维护性,还可借助防卫式声明防止重复包含。
类的声明则是定义用户自定义类型的关键。在类里可声明数据成员与成员函数,还能通过访问控制符(public、private、protected)管控成员的访问权限。类的声明一般置于头文件,而实现可放在源文件,如此能实现接口与实现分离,增强代码的模块化与可复用性。