文章

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
仅做声明、无需访问成员函数✅ 前向声明

源文件中(*.cpp)

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

常见误区

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