13.C++中static的应用及文件包含
创始人
2025-05-30 05:50:36

文章目录

    • 1.文件包含
    • 2.static的作用
    • 参考资料


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


1.文件包含

.h文件中主要是用来声明函数和变量,有时候也可以用来定义函数和变量。

.h中最常见的就是重复包含,看下面例子

文件add.h:

int c = 10;
int add(int &a, int &b);

文件add.cpp:

#include "add.h"
int add(int &a, int &b)
{return a + b;
}

文件addA.h:

#include "add.h"
int addA(int a, int b);

文件addA.cpp:

#include "addA.h"
int addA(int a, int b)
{return add(a, b);
}

文件addB.h:

#include "add.h"
int addB(int a, int b);

文件addA.cpp:

#include "addB.h"
int addB(int a, int b)
{return add(a, b);
}

文件main.cpp:

#include #include "addA.h"
#include "addB.h"
int main(int argc, char **argv)
{int a = 1, b = 2;std::cout << addA(a, b) << " " << addB(a, b) << std::endl;return 0;
}

学过C++的肯定都知道上面代码编译会报错,因为包含add.h两次,导致重复声明了c变量。

g++ main.cpp -o m.oIn file included from addB.h:3,from main.cpp:4:
add.h:3:5: error: redefinition of ‘int c’3 | int c = 10;|     ^
In file included from addA.h:3,from main.cpp:3:
add.h:3:5: note: ‘int c’ previously defined here3 | int c = 10;

这种情况下解决办法最常用的就是在每个头文件中添加宏:

#ifndef __ADD_H__
#define __ADD_H__
...
#endif // __ADD_H__

然后,再编译发现就会发现可以编译成功。

依次将上面四个源文件编译完成:

g++ main.cpp -o m.o
g++ add.cpp -o a.o
g++ addA.cpp -o A.o
g++ addB.cpp -o b.o

链接时会导致报错:

g++ a.o A.o B.o m.o -o m
/usr/bin/ld: A.o:(.data+0x0): multiple definition of `c'; a.o:(.data+0x0): first defined here
/usr/bin/ld: B.o:(.data+0x0): multiple definition of `c'; a.o:(.data+0x0): first defined here
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status

为什么会出错呢? 按照条件编译,add.h并没有重复包含,可是还是提示变量a重复定义了。 对比第一次报错,不加条件编译在编译时就报错,加了条件编译,编译能通过,但链接时报错。

在这里注意的是,变量/函数/类/结构体的重复定义不仅会发生在源程序编译的时候,在目标程序链接的时候同样也有可能发生。

c/c++编译的基本单元是.c.cpp文件,各个基本单元的编译是相互独立的,#ifndef等条件编译只能保证在一个基本单元(单独的.c.cpp文件)中头文件不会被重复编译,但是无法保证两个或者更多基本单元中相同的头文件不会被重复编译。

头文件尽量只有声明,不要有定义。

解决上面问题的一种办法是,在add.h中定义int c = 10;时加static修饰符,如下:

add.h文件:

#ifndef __ADD_H__
#define __ADD_H__
static int c = 10;
int add(int &a, int &b);
#endif // __ADD_H__

然后,就能编译通过了,static关键字在这里修饰定义的变量时局部变量,只在当前文件中可见。在编译A.oB.o时会在两个编译文件中分别定义变量c,因此就可以编译通过了,同样static也能用来修饰函数,表示函数只能在当前文件中被调用。函数的不同点在于,如果static修饰的函数定义在.h文件中,那么其他包含.h的文件能调用static修饰的函数,每个文件使用的是一个单独的函数;如果,static修饰的函数声明在.h文件中,定义在.cpp文件中,那么这个函数对其他文件将不可见。

// case 1:
// add.h
#ifndef __ADD_H__
#define __ADD_H__
static int add(int &a, int &b)
{return a + b;
}
#endif // __ADD_H__// case 2:
// add.h
#ifndef __ADD_H__
#define __ADD_H__
static int add(int &a, int &b);
#endif // __ADD_H__
// add.cpp
#include "add.h"
int add(int &a, int &b)
{return a + b;
}
// addA.h
#include "add.h"
int addA(int &a, int &b);
// addA.cpp
#include "addA.h"
int addA(int &a, int &b)
{return add(a, b); // error, can't invoke add function since it is a static function
}

2.static的作用

由上面的例子看到了static的一种应用是限制函数或变量的作用域在当前源文件。static另外一个作用是定义静态数据和类中定义属于类而不是对象的成员

// main.cpp
int accumulate(int a)
{static int cc = 0;cc += a;return cc;
}int main(int argc, char** argv)
{int re = 0;for(auto i=0; i<3; i++){re = accumulate(i);}std::cout << re << std::endl;return 0;
}

上面累加函数accumulate中声明的cc变量是静态数据,保存在静态存储区(全局变量存储区), 因此延长了cc的生命周期,但static并不改变变量的作用域,因此还是只能在accumulate函数中使用。

此外就是static还可以用来修饰类中的数据成员或者成员函数,这样数据成员就保存在类的内存空间上而不是类实例对象的内存空间上。static修饰的成员函数中没有this指针,因此不能访问类中的非静态数据成员和方法。

类中的static数据成员,仍然受private等访问权限修饰符控制,若需通过类名::变量名来使用,需将其声明为public类型。

类中的static数据成员,需在类外初始化。

#include class Example {public:Example() : b(0) {};public:static int a;private:int b;
};int Example::a = 10;
int main(int argc, char **argv)
{std::cout << Example::a << std::endl;return 0;
}

参考资料

  • 1.https://blog.csdn.net/ruibin_cao/article/details/98631372
  • 2.https://www.tutorialspoint.com/how-to-create-a-static-class-in-cplusplus

相关内容

热门资讯

股价暴涨!三大AMC划归 中央... 21世纪经济报道 记者 崔文静 北京报道6月9日,信达证券股价大涨10.01%,报收16.04元。与...
特朗普还能折腾出美股的新高吗? 特朗普执政时期对美股产生了复杂的影响。一方面,他的经济政策举措,如减税等,在一定程度上刺激了企业盈利...
“常温乳酸菌第一股”离奇暴涨,... 来源 | 深蓝财经撰文 | 王鑫A股再现魔幻剧情!1不服监管,一路暴涨你喝过味动力乳酸菌饮料吗?这款...
都在对标的星巴克,更“不务正业... 来源 | 深蓝财经撰文 | 吴瑞馨奶茶咖啡市场正激战得如火如荼,星巴克零帧起手,以降价主动出击下午茶...
新四军江北指挥部为何会选址东汤... 庐江县汤池镇 苍翠蓊郁、鸟鸣起伏的松林间 坐落着新四军江北指挥部纪念馆 数百件珍贵文物和图文资料等 ...
国家亮剑,中小学最严红线来了 ... 作者 | 幸凯国家亮剑,中小学最严红线来了,以后将越来越严。5月27日,教育部印发《关于开展基础教育...
AI快进到补贴大战:从Perp... 在科技领域,一场激烈的补贴大战正悄然拉开帷幕。从 Perplexity 到 Gemini,众多 AI...
美股期货下跌!500名美海军陆... 每经编辑|毕陆名 美国洛杉矶局势升级,美股应声下跌。北京时间周一,美股三大指数期货开盘后一路走低,...
江西“首富”李仙德,财富缩水超... 光伏行业分化,已成大趋势。 今年一季度如果说哪家光伏巨头的表现最让外界大跌眼镜,那么晶科能源一定“榜...
国产 AI 初创企业硅基流动完... IT之家 6 月 9 日消息,国内 AI 初创企业硅基流动(SiliconFlow)今日发文宣布,已...
公募收费模式变革:你的基金管理... 证监会的一纸新规,正在悄然改变公募基金的收费模式。5月初发布的《推动公募基金高质量发展行动方案》明确...
巨富金业:特朗普派兵洛杉矶应对... 一、事件背景:联邦与州政府的宪法博弈 当地时间6月7日,美国总统特朗普签署行政命令,向洛杉矶部署20...
蔚来穿破黎明 蔚来穿破黎明 钄... 本文来源:时代周报 作者:林健“四季度要全面达成经营目标”,蔚来创始人、董事长、CEO李斌再次强调。...
科技创新债券“满月”!147家...   中新经纬6月9日电 据交易商协会网站9日消息,截至6月7日,科技创新债券推出首月,全市场147家...
供应链金融,真的是万恶之源? 供应链金融并非万恶之源。它是一种创新的金融模式,通过整合供应链上的资金流、物流和信息流,为供应链中的...
全球最大室内滑雪场动工,预计2... 太仓阿尔卑斯国际度假区二期项目开工活动现场记者/ 韩璐 编辑/ 谭璐6月上旬,太仓阿尔卑斯国际度假区...
泡泡玛特王宁成“河南新首富”,... 泡泡玛特市值又创新高!作者 | 于婞编辑丨武丽娟来源 | 野马财经还有人不知道LABUBU吗?这个拥...
6连板共创草坪:国内相关足球体... 6月9日,6连板江苏共创人造草坪股份有限公司(共创草坪,605099.SH)发布股票交易异常波动公告...
楚天龙:数字货币桥等项目存在商... 6月9日晚间,楚天龙股份有限公司(楚天龙,003040.SZ)发布股票交易异动公告称,公司关注到近期...
汇川技术6名员工获联合动力股权... 苏州汇川联合动力系统股份有限公司(以下简称“联合动力”)向深交所递交了创业板IPO招股说明书,在20...
识局带领数家企业“闪电”探访越... 文/识局君(识局微信公共账号zhijuzk)6月9日,识局安排数家企业前往越南兴富工业园区,并开展了...
“带病闯关”项目频现一案多罚,... 今年以来,IPO监管延续从严态势,“一案多罚”的情况屡屡出现。就在近期,因一单“带病闯关”的IPO项...
识局安排杭州六小龙企业反向考察... 文/识局招商团队(识局微信公共账号zhijuzk)6月9日,周一。识局安排杭州六小龙企业反向考察江苏...
中国啤酒抢高端告一段落 文 | 巨潮WAVE,作者|侯恬,编辑|杨旭然 这两年中国的啤酒行业开启了冰镇模式,降温明显。 从去...
巴西财政部副部长:加强对华关系... 【文/观察者网 王一】金融业正成为中巴合作的一个新增长点。英国《金融时报》6月9日报道称,在美国挑起...
泡泡玛特创始人王宁成河南新首富... 王宁跻身河南首富,蜂巧资本东方证券等早期投资机构收益颇丰 6月6日,根据福布斯实时富豪榜,泡泡玛特...
比亚迪李云飞微博回应被删,传王... 6月8日,针对近期常被提起的“常压油箱”事件和车圈“恒大”争议,比亚迪品牌及公关总经理李云飞首次公开...
日本动漫创作者,正悄悄用上中国... 在全球动漫强国日本,正悄然经历着一场前所未有的变化。今年4月,日本首部主要由AI制作的动漫《Twin...
龙虎榜丨机构今日买入这18股,... 盘后数据显示,6月9日龙虎榜中,共33只个股出现了机构的身影,有18只股票呈现机构净买入,15只股票...