ArtCraft:一套可复现的创意操作系统
2026/10/19 10:55:22
一个声明就是一个定义,除非 :
·它声明了一个没有具体说明函数体的函数;
·它包含一个extern说明符,并且没有初始化程序或函数体;
·它是一个类定义内的静态类数据成员的声明;
·它是一个类名的声明;
·它是一个typedef声明。
一个定义就是一个声明,除非:
·它定义了一个静态类数据成员;
·它定义了一个non-inline成员函数。
这段话的核心是:声明和定义高度重叠,但有特定例外—— 先默认「声明=定义」,再列例外;再默认「定义=声明」,再列例外。下面逐句拆解,结合例子理解。
这句话的意思是:绝大多数声明会同时完成定义,只有这5种情况,声明仅仅是「声明」,不会成为「定义」。
voidf();// 仅声明:告诉编译器有个返回void、无参数的函数f,但没说f做什么voidf(){// 声明+定义:既告诉编译器有f,又给出函数体(实现)std::cout<<"hello";}extern关键字的核心含义是「这个名字的定义在别处」,因此带extern且无初始化/函数体的声明,仅起「告知存在」的作用,不分配内存/不提供实现。extern变量带初始化,或extern函数带函数体,就变成了定义!externinta;// 仅声明:a的定义在其他文件/本文件后续位置externinta=10;// 声明+定义:虽然有extern,但初始化了,分配内存并赋值externvoidf();// 仅声明:f的定义在别处externvoidf(){}// 声明+定义:有函数体,是定义classA{staticintx;// 仅声明:告诉编译器A有个静态成员x,但不分配内存};intA::x=0;// 定义:为x分配内存并初始化,这才是真正的定义(C++17后可加inline让类内定义生效:static inline int x = 0;,此时类内既是声明也是定义)classB;// 仅声明(前向声明):编译器知道B是类,但不知道B有什么structC;// 同理,结构体前向声明也是仅声明classB{// 声明+定义:定义了B的成员,编译器能确定B的大小和布局inty;voidg();};typedef只是给已有类型起「别名」,没有定义新类型,也不分配内存,因此仅为声明。typedefintInt;// 仅声明:Int是int的别名,无内存分配,无新类型定义usingInt=int;// C++11的类型别名,和typedef等价,也是仅声明这句话的核心是:绝大多数定义本身也是声明(因为定义必然先告知编译器「这个名字存在、类型是什么」),但这2种情况中,「定义」是「对已有声明的补充」,而非「新的声明」—— 即定义本身不承担「首次声明」的角色。
classA{staticintx;// 首次声明:这是声明,不是定义};intA::x=0;// 定义:补充实现(分配内存),但不是新的声明(声明已在类内完成)这里的int A::x = 0是定义,但它不是「声明」(因为声明已经在类内做了),因此违反「定义就是声明」的默认规则。classA{voidf();// 首次声明:声明了成员函数finlinevoidg(){}// 类内inline定义:既是声明也是定义(符合默认规则)};voidA::f(){}// non-inline定义:仅提供实现,不是新的声明(声明已在类内完成)inlinevoidA::g(){}// 类外inline定义:仍是声明+定义(符合默认规则)这里的void A::f() { }是定义,但不是「新的声明」,因此属于例外。extern变量带初始化 = 定义(而非仅声明);