C++前向声明

#前向声明 #Cpp

前向声明(Forward Declaration) 是一种告诉编译器某个类型(如类、结构体或函数)存在的方式,而不提供该类型的完整定义。在前向声明中,我们只需要声明该类型的名称,但并不需要包含具体的定义细节。这对于减少编译依赖、提高编译速度有很大帮助。

什么时候使用前向声明?

  1. 只声明指针或引用:如果你只需要在某个类或函数中使用指向某类型的指针或引用,而不需要访问其内部成员时,可以使用前向声明。
  2. 减少编译依赖:前向声明能够减少不必要的头文件包含,使得代码模块之间的依赖关系更加简洁,从而减少编译时间和复杂度。

举个例子,假设我们有一个 Person 结构体,他在这个person.h文件中有完整的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef PERSON_H
#define PERSON_H

#include <string>

struct Person {
std::string name;
int age;

Person(const std::string& n, int a) : name(n), age(a) {}
};

#endif

那比方说我们有一个类,需要使用到这个Person结构体。我们先不使用这个前向声明:

company.h(不使用前向声明,直接包含 person.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef COMPANY_H
#define COMPANY_H

#include "person.h" // 直接包含 Person 的定义

struct Company {
std::string name;
Person* employee; // 指向 Person 结构体的指针

Company(const std::string& n) : name(n), employee(nullptr) {}

void hireEmployee(Person* employee);
void printEmployeeInfo() const;
};

#endif

而这个company.cpp就应该是这么写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "company.h"
#include <iostream>

void Company::hireEmployee(Person* employee) {
this->employee = employee;
}

void Company::printEmployeeInfo() const {
if (employee) {
std::cout << "Employee: " << employee->name << ", Age: " << employee->age << std::endl;
} else {
std::cout << "No employee hired." << std::endl;
}
}

那如果我们使用了前向声明,那么这个company.hcompany.cpp就应该是这么写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef COMPANY_H
#define COMPANY_H

// 前向声明 Person 结构体
struct Person;

struct Company {
std::string name;
Person* employee; // 指向 Person 结构体的指针

Company(const std::string& n) : name(n), employee(nullptr) {}

void hireEmployee(Person* employee); // 使用指向 Person 的指针
void printEmployeeInfo() const;
};

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "company.h"
#include "person.h" // 包含 Person 的完整定义

#include <iostream>

void Company::hireEmployee(Person* employee) {
this->employee = employee;
}

void Company::printEmployeeInfo() const {
if (employee) {
std::cout << "Employee: " << employee->name << ", Age: " << employee->age << std::endl;
} else {
std::cout << "No employee hired." << std::endl;
}
}

这样一来,虽然看上去没什么变化,但是他能够避免了直接包含 person.h,使得 company.h 更加简洁。不使用前向声明意味着 company.h 依赖于 person.h,如果 person.h 中有任何变化,所有包含 company.h 的文件都需要重新编译,这会增加编译时间和复杂度。同时前向声明也可以用来打破循环依赖,分解依赖关系。

C++项目的编写中其实有一个原则,就是最小化头文件依赖。即尽可能减少头文件中包含的其他头文件,以减少编译依赖,避免不必要的重编译。.h文件都应该尽量的让这个.c或者.cpp文件去包含而不是在头文件中直接包含。


C++前向声明
http://zerohzzzz.github.io/2024/09/06/C++前向声明/
Author
ZeroHzzzz
Posted on
September 6, 2024
Licensed under