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

相关内容

热门资讯

铁路“静音车厢”列车数量增加 ...   出门坐高铁,有人想安静地看看书、休息一会儿,也有人希望能专心处理工作。但车厢里的交谈声、电子设备...
贵州千年侗寨非遗织就乡村振兴锦...   新华社贵阳1月17日电(记者周宣妮)走进贵州省黎平县肇兴侗寨,流水蜿蜒、青山绿水环抱着千年鼓楼,...
斯帕莱蒂:卡利亚里10个人轮流... 在这个竞争激烈的意甲赛季,谁能想到尤文图斯竟然在客场以0-1不敌卡利亚里?这场比赛让不少球迷大跌眼镜...
商业秘密|宝可梦卡牌价格飙涨至... 热钱加速涌入的背景下,市场迎来“卡牌第一股”的路还有多长? 近日,有宝可梦集换式卡牌的买家向第一财经...
长源东谷:公司采用行业内普遍适... 证券日报网讯 1月16日,长源东谷在互动平台回答投资者提问时表示,公司采用行业内普遍适用的“订单式生...