QT - static用法

C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。

一、面向过程设计中的static

1、静态全局变量
在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下:

//Example 1
#include
void fn();
static int n;   //定义静态全局变量
void main()
{
n=20;
cout<<n<<endl;
fn();
}

void fn()
{
n++;
cout<<n<<endl;
}

静态全局变量有以下特点:

该变量在全局数据区分配内存;

未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);

静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;

静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下图:

代码区 全局数据区 堆区 栈区

一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将

1.static int n; //定义静态全局变量

改为

1.int n;

//定义全局变量
程序照样正常运行。

的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

静态全局变量不能被其它文件所用;

其它文件中可以定义相同名字的变量,不会发生冲突;

您可以将上述示例代码改为如下:

01.//Example 2
02.//File1
03.#include
04.void fn();
05.static int n;//定义静态全局变量
06.void main()
07.{
08.n=20;
09.cout<<n<<endl;
10.fn();
11.}
12.
13.//File2
14.#include
15.extern int n;
16.void fn()
17.{
18.n++;
19.cout<<n<<endl;
20.}

编译并运行Example 2,您就会发现上述代码可以分别通过编译,但运行时出现错误。试着将

1.static int n;//定义静态全局变量

改为

1.int n;//定义全局变量

再次编译运行程序,细心体会全局变量和静态全局变量的区别。

2、静态局部变量
在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。

我们先举一个静态局部变量的例子,如下:

01.//Example 3
02.#include
03.void fn();
04.void main()
05.{
06.fn();
07.fn();
08.fn();
09.}
10.void fn()
11.{
12.static n=10;
13.cout<<n<<endl;
14.n++;
15.}

通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。

但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。

静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。

静态局部变量有以下特点:

该变量在全局数据区分配内存;

静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;

静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;

它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

3、静态函数

在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

静态函数的例子:

01.//Example 4
02.#include
03.static void fn();//声明静态函数
04.void main()
05.{
06.fn();
07.}
08.void fn()//定义静态函数
09.{
10.int n=10;
11.cout<<n<<endl;
12.}

定义静态函数的好处:

静态函数不能被其它文件所用; 其它文件中可以定义相同名字的函数,不会发生冲突;

二、面向对象的static关键字(类中的static关键字)
1、静态数据成员
在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。

01.//Example 5
02.#include
03.class
Myclass
04.{
05.public:Myclass(int a,int b,int c);
07.void GetSum();
08.private:
09.int a,b,c;
10.static int Sum;//声明静态数据成员
11.};
12.int Myclass::Sum=0; //定义并初始化静态数据成员
13.
14. Myclass::Myclass(int a,int b,int c)
15.{
16.this->a=a;
17.this->b=b;
18.this->c=c;
19.Sum+=a+b+c;
20.}
21.
22.void Myclass::GetSum()
23.{
24.cout<<"Sum="<<Sum<<endl;
25.}
26.
27.void main()
28.{
29.Myclass M(1,2,3);
30.M.GetSum();
31.Myclass N(4,5,6);
32.N.GetSum();
33.M.GetSum();
34.
35.}

可以看出,静态数据成员有以下特点:

对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;

静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;

静态数据成员和普通数据成员一样遵从public,protected,private访问规则;

因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;

静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:

<数据类型><类名>::<静态数据成员名>=<值>

类的静态数据成员有两种访问形式:

<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;

静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;

同全局变量相比,使用静态数据成员有两个优势:

1.静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
2.可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

2、静态成员函数
与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。

01.//Example 6
02.#include
03.class Myclass
04.
05.public:
06.Myclass(int a,int b,int c);
07.static void GetSum();/声明静态成员函数
08.private:
09.int a,b,c;
10.static int Sum;//声明静态数据成员
11.};
12.int Myclass::Sum=0;//定义并初始化静态数据成员
13.
14.Myclass::Myclass(int a,int b,int c)
15.{
16.this->a=a;
17.this->b=b;
18.this->c=c;
19.Sum+=a+b+c;//非静态成员函数可以访问静态数据成员
20.}
21.
22.void Myclass::GetSum()//静态成员函数的实现
23.{
24.// cout<<a<<endl; //错误代码,a是非静态数据成员
25.cout<<"Sum="<<Sum<<endl;
26.}
27.
28.void main()
29.{
30.Myclass M(1,2,3);
31.M.GetSum();
32.Myclass N(4,5,6);
33.N.GetSum();
34.Myclass::GetSum();
35.}

关于静态成员函数,可以总结为以下几点:

出现在类体外的函数定义不能指定关键字static;

静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

非静态成员函数可以任意地访问静态成员函数和静态数据成员;

静态成员函数不能访问非静态成员函数和非静态数据成员;

由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:

<类名>::<静态成员函数名>(<参数表>)

调用类的静态成员函数。

<think>好的,用户现在遇到了一个问题,就是在Visual Studio里右键新建项目时找不到Qt Static Library选项。之前他们询问过如何在Qt+VS项目中添加多个子项目,现在可能是在实际操作中遇到了这个选项缺失的问题。 首先,我需要回想一下Qt在Visual Studio中的集成情况。通常,安装Qt VS Tools后,新建项目时会有各种Qt项目模板,包括静态库。所以用户的问题可能是因为没有正确安装或配置Qt VS Tools,或者安装的版本不支持静态库。 接下来,我应该考虑可能的原因: 1. Qt VS Tools未正确安装或未启用。 2. 安装的Qt版本本身不支持静态库,需要单独构建静态版本的Qt。 3. 项目模板可能被过滤或分类在其他位置,用户没找到。 4. Visual Studio版本或Qt VS Tools版本过旧,不支持静态库模板。 然后,解决方案需要分步骤指导用户检查安装、配置静态库支持、或者手动创建静态库项目。同时,需要提醒用户静态库在Qt中的使用注意事项,比如依赖的模块和部署时的兼容性。 另外,用户可能需要替代方案,比如创建动态库然后静态链接,或者使用子目录项目管理。这部分也应该包含在回答中,确保用户有其他选择。 最后,确保回答结构清晰,逐步引导用户排查问题,并提供详细的步骤,比如如何检查Qt VS Tools的安装,如何构建静态Qt库,以及手动配置.pro文件的方法。同时,注意使用用户容易理解的语言,避免技术术语过多,但又要准确。</think>在 Visual Studio 中创建 Qt 静态库项目时若找不到 "Qt Static Library" 模板,可通过以下方案解决: --- ### 一、问题原因分析 1. **基础环境缺失** - Qt VS Tools 插件未完整安装 - 未安装静态库开发组件(默认 Qt 安装为动态库) 2. **模板分类问题** - 项目类型筛选器设置不当 - VS 版本与新模板的兼容性问题 --- ### 二、解决方案步骤 #### 方案 1:检查 Qt 环境配置 1. **验证 Qt 静态库支持** - 打开 Qt 安装目录(如 `C:\Qt`) - 检查是否存在 `Static` 或 `Static Libraries` 子目录 - 若缺失,需通过 **Qt Maintenance Tool** 重新安装: - 勾选组件时选择 `Qt > [版本] > MSVC [编译器] > Qt Static Libraries` 2. **配置 VS 开发环境** ```powershell # 示例:手动注册静态库套件(需管理员权限) cd C:\Qt\5.15.2\msvc2019_static configure -static -prefix "C:\Qt\5.15.2-static" nmake ``` #### 方案 2:手动创建静态库 1. **新建空白 Qt 项目** - 右键解决方案 → 添加 → 新建项目 → 选择 `Qt Empty Project` - 命名为 `MyStaticLib`(建议名称带 `Lib` 标识) 2. **修改项目配置**(关键步骤) 在 `.pro` 文件中添加: ```qmake TEMPLATE = lib CONFIG += staticlib QT += core # 按需添加其他模块(如 gui、network) ``` 3. **添加源码文件** - 右键项目 → 添加 → 新建项 → 创建 `.h` 头文件和 `.cpp` 实现文件 - 示例头文件声明: ```cpp #pragma once class MyMath { public: static int add(int a, int b); }; ``` #### 方案 3:使用动态库转静态链接 在无法使用静态库时,可通过动态库强制静态链接: ```qmake # 在主项目的 .pro 文件中添加 CONFIG += static QMAKE_LFLAGS += /NODEFAULTLIB:MSVCRT ``` --- ### 三、配置验证流程 1. **生成验证** - 编译子项目 → 检查输出目录是否生成 `.lib` 文件(Windows)或 `.a` 文件(Linux/MacOS) 2. **链接测试** ```cpp // 在主项目代码中调用 #include "MyMath.h" int result = MyMath::add(2, 3); ``` 3. **依赖检查**(重要) ```qmake # 在主项目.pro 中确保包含 LIBS += -L$$OUT_PWD/../MyStaticLib -lMyStaticLib INCLUDEPATH += $$PWD/../MyStaticLib ``` --- ### 四、常见问题处理 | 错误类型 | 解决方案 | |-------------------------|--------------------------------------------------------------------------| | LNK2019 未解析符号 | 检查类声明是否包含 `__declspec(dllexport)`(Windows)或 Q_DECL_EXPORT | | 找不到 .lib 文件 | 确认子项目生成路径是否在 `LIBS` 路径中 | | Qt 模块未链接 | 在静态库的 `.pro` 中添加 `QT += [模块名]` | --- ### 五、替代方案建议 1. **创建子目录项目** ```qmake # 在解决方案根目录的 .pro 中 TEMPLATE = subdirs SUBDIRS = App \ StaticLib ``` 2. **使用 CMake 管理** ```cmake add_library(MyStaticLib STATIC src/mylib.cpp) target_link_libraries(MainApp PRIVATE MyStaticLib) ``` --- **建议优先使用 Qt Maintenance Tool 安装预编译的静态库版本**。若需自定义构建,注意不同平台的静态库命名规范差异(Windows 需 `.lib`,Linux/MacOS 需 `.a`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值