文章

C++前向声明

前向声明用于声明类存在,仅用于指针或引用,能减少依赖、提升编译速度。访问成员或用作对象时必须 #include。

C++前向声明

C++ 前向声明

前向声明就是:告诉编译器某个类/结构/函数存在,但此处不提供完整定义

1
2
3
class MyClass;    // 前向声明类
struct Node;      // 前向声明结构体
void foo(int);    // 前向声明函数

前向声明 VS #include

对比项前向声明#include 头文件
是否看到类完整定义否,只知道“有这个类”是,看到所有成员/结构体定义
编译器能否生成代码否,无法访问成员或构造可以生成完整代码
用途减少依赖,避免循环使用对象成员、继承、构造等
是否推荐用于头文件是,尽量前向声明除非必须使用完整类型

前向声明适用的场景

场景示例代码是否需要 include
只用到指针class A; A* a;不需要
只用到引用class A; void func(A&);不需要
声明函数参数为指针/引用void setTarget(Target*);不需要
声明类成员为指针/引用Target* target_;不需要
函数参数中 forward-declareclass Foo; void f(Foo* p);不需要

必须 #include 的情况

场景原因是否能前向声明
成员变量是对象需要知道对象大小不行
访问成员函数需要知道成员结构不行
构造对象需要知道构造函数不行
调用析构函数(如 delete需要完整析构函数不行
类继承另一个类必须知道完整基类结构不行
使用智能指针(shared_ptr默认 deleter 需要完整类型不行(除非自定义 deleter)
RTTI 操作(dynamic_cast, typeid需要完整类定义和 RTTI 信息不行

头文件中

用法建议
只用指针/引用前向声明
有成员变量是对象必须 include
类作为参数(按值传递)必须 include
继承自另一个类必须 include
仅做声明、无需访问成员函数前向声明

源文件中

  • 总是可以 #include 头文件,因为是实现部分。
  • 一旦访问成员函数、构造函数或 delete,必须 include。
  • 即使是 ptr->xxx(),也需要 include。
  • 如果只是 ptr_ = other_ptr; 赋值,不需要 include。

常见误区

误区正确解释
“指针用处都不用 include”错,如果访问成员函数就必须 include
“shared_ptr 可以不 include”错,shared_ptr<T> 的默认 deleter 会调用析构函数
“delete 指针时不需要 include”错,delete 需要知道类的析构函数定义
“类之间循环引用就直接 include”错,会导致互相 include 卡住;应用前向声明解决

总而言之:

  • 尽量在头文件使用前向声明 → 减少依赖,加快编译。
  • 只有当必须知道类的完整定义(成员对象、按值传参、调用方法)时,才 #include 对应头文件。
本文由作者按照 CC BY 4.0 进行授权