如何使用全局变量QT

兩種方法:

第一:使用extern關鍵字聲明(不推薦,破壞了封裝性)
第二:新建一個類,存放全局的變量,函數


 


第一:使用extern關鍵字聲明(不推薦,破壞了封裝性)

在一个头文件中声明int var_name全局变量,在另一个cpp文件中引用此变量: extern int var_name;
指出var_name是在外部文件定时的变量,编译器会自动在所有文件中查找var_name的定义,如:
aaa.h:

#ifndef AAA_H
#define AAA_H
int var_name;

static bool fun()

{

dosth

}
#endif // AAA_H

main.cpp:

#include <QtCore/QCoreApplication>
#include "aaa.h"
#include <qdebug.h>
extern int var_name;//只需导入即可,不可再定义,函數可用也可不用extren聲明
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

if (!dun()) 

return 1;
    qDebug()<<var_name;//全局整形变量会赋默认值0
    return a.exec();
}
第二:新建一個類,存放全局的變量,函數(static关键字)

在.h文件下定义类 
class   temp{ 
private: 
         static  int   x; 

在.cpp下定义 
int   temp::x=0; 
这样就可以当全局变量使用了,

以下为转来的实例

qt中的全局变量_xiehuin的博客-优快云博客

这一段开发一个程序,需要多个源文件,包括若干个头文件和若干个定义文件。因此如何在多个源程序间开发传递变量就成了一个关键问题。一般来说在多个源程序间传递变量大概有两种方法,一是利用extern声明全局变量来进行传递,二是将全局变量定义成一个类的静态变量,通过类名::变量名进行调用。

通过若干次调试,第一种方法终于成功,现将注意要点记录如下:

WILD.H文件:

 #ifndef FORM1_H
#define FORM1_H

/*class wild
{
  public:
    static int sum;    //推荐
};*/

extern int num;   //不推荐

#endif

WILD.CPP文件:

#include "wild.h"

//wild::sum=10;   //推荐
int num=10;  //不推荐

FORM1.H文件:

/****************************************************************************
** Form interface generated from reading ui file 'form1.ui'
**
** Created: 六  2月 9 11:13:23 2008
**      by: The User Interface Compiler ($Id: qt/main.cpp   3.1.1   edited Nov 21 17:40 $)
**
** WARNING! All changes made in this file will be lost!
****************************************************************************/

#ifndef FORM1_H
#define FORM1_H

#include <qvariant.h>
#include <qwidget.h>
//#include "wild.h"

class QVBoxLayout;
class QHBoxLayout;
class QGridLayout;
class QLineEdit;
class QPushButton;
//class wild;

class Form1 : public QWidget
{
    Q_OBJECT

public:
    Form1( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
    ~Form1();

    QLineEdit* lineEdit1;
    QPushButton* pushButton1;

protected:
     
protected slots:
    virtual void languageChange();
    virtual void sett();
};

#endif // FORM1_H

FORM1.CPP文件:

/****************************************************************************
** Form implementation generated from reading ui file 'form1.ui'
**
** Created: 六  2月 9 11:13:35 2008
**      by: The User Interface Compiler ($Id: qt/main.cpp   3.1.1   edited Nov 21 17:40 $)
**
** WARNING! All changes made in this file will be lost!
****************************************************************************/

#include "form1.h"
//#include "wild.h"

#include <qvariant.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qlayout.h>
#include <qtooltip.h>
#include <qwhatsthis.h>
#include <qimage.h>
#include <qpixmap.h>
#include <iostream.h>

 extern int num;    //不推荐

/* 
 *  Constructs a Form1 as a child of 'parent', with the 
 *  name 'name' and widget flags set to 'f'.
 */
Form1::Form1( QWidget* parent, const char* name, WFlags fl )
    : QWidget( parent, name, fl )
{
    if ( !name )
 setName( "Form1" );

    lineEdit1 = new QLineEdit( this, "lineEdit1" );
    lineEdit1->setGeometry( QRect( 50, 80, 191, 61 ) );

    pushButton1 = new QPushButton( this, "pushButton1" );
    pushButton1->setGeometry( QRect( 60, 190, 161, 71 ) );
    languageChange();
    resize( QSize(600, 480).expandedTo(minimumSizeHint()) );

    // signals and slots connections
    connect( pushButton1, SIGNAL( clicked() ), this, SLOT( sett() ) );
    connect( pushButton1, SIGNAL( clicked() ), this, SLOT( adjustSize() ) );
}

/*
 *  Destroys the object and frees any allocated resources
 */
Form1::~Form1()
{
    // no need to delete child widgets, Qt does it all for us
}

/*
 *  Sets the strings of the subwidgets using the current
 *  language.
 */
void Form1::languageChange()
{
    setCaption( tr( "Form1" ) );
    pushButton1->setText( tr( "pushButton1" ) );
}

void Form1::sett()
{
    //lineEdit1->setText(wild::sum);
 
    cout <<num;
}

MAIN文件:

#include <qapplication.h>
#include "form1.h"

int main( int argc, char ** argv )
{
    QApplication a( argc, argv );
    Form1 w;
    w.show();
    a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
    return a.exec();
}

要注意以下几点:

(1)头文件中声明全局变量时要加上extern关键字,全局变量的定义可以直接加在头文件中,也可以放到定义文件中,但在定义文件中的时候要注意加上变量类型符。

(2)调用全局变量的源文件可以不用包含全局变量所在的头文件,但最好是加上,因为几个文件间的相互包含makefile都给解决了。

(3)使用全局变量的时候需先声明,如extern int num;将其放在本文件的头文件的前面。(不推荐)

以上就是使用extern来解决全局变量的问题,但是这种方法有弊端,主要是如果在系统库函数中有和定义的全局变量同名的变量,将会造成冲突,其二是其结构不符合面向对象的思想,因此还是使用第二种方法为好。

實例2

//globalsize.h
#ifndef GLOBALSIZE_H
#define GLOBALSIZE_H
#include <QtGui>


class GlobalSize
{
public:
    static QSize size;


    static void setSize(QSize s);
    static QSize getSize();


};


#endif // GLOBALSIZE_H


//globalsize.cpp
#include "globalsize.h"


QSize GlobalSize::size = QSize(0,0);




void GlobalSize::setSize(QSize s)
{
    size = s;
}
QSize GlobalSize::getSize()
{
    return size;
}

辅助知识

面向对象的static关键字(类中的static关键字)
静态数据成员有以下特点:
  对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份 拷 贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共 用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。语句int Myclass::Sum=0;是定义静态数据成员;
  静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
  因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
  静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
  <数据类型><类名>::<静态数据成员名>=<值>
  类的静态数据成员有两种访问形式:
  <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
  如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
  静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成 员。这 有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次, 则所有存款类对象的利息全改变过来了;
  同全局变量相比,使用静态数据成员有两个优势:
  静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

  2、静态成员函数
  与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的 内部 实现,属于类定义的一部分。 普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指 针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。
关于静态成员函数,可以总结为以下几点:
  出现在类体外的函数定义不能指定关键字static;
  静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
  非静态成员函数可以任意地访问静态成员函数和静态数据成员;
  静态成员函数不能访问非静态成员函数和非静态数据成员;
  由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
  调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
  <类名>::<静态成员函数名>(<参数表>)
  调用类的静态成员函数。

<think>嗯,用户问的是QT是否推荐使用全局变量。首先,我得回忆一下QT框架的一些最佳实践。全局变量在编程中通常是不被推荐的,因为它们可能导致代码耦合度高、难以维护和测试。不过,具体情况具体分析。 QT作为一个GUI框架,可能有自己的机制来处理跨组件的通信和数据共享。比如,信号和槽机制就是QT的核心特性之一,用来在对象之间传递消息。另外,单例模式或者使用应用程序级别的对象(如QApplication的子)来管理共享数据可能比全局变量更合适。 用户可能是在开发过程中遇到了需要在多个或组件之间共享数据的情况,考虑使用全局变量,但不确定是否合适。他们可能关心如何在不使用全局变量的情况下,有效地在QT应用中管理共享状态。 需要提到全局变量的缺点,比如破坏封装性、增加调试难度、线程安全问题等。然后给出QT推荐的替代方案,比如使用信号和槽、单例模式、依赖注入,或者利用QT的模型/视图架构来共享数据。 还要注意,有时候在小型项目或快速原型开发中,全局变量可能看起来方便,但随着项目规模扩大,维护成本会增加。因此,建议用户遵循QT的设计模式,避免全局变量,以提高代码的可维护性和可扩展性。 最后,总结一下,明确回答不推荐使用全局变量,并给出替代方法,帮助用户理解如何在QT框架下更好地管理数据。</think>在Qt开发中,**不推荐使用全局变量**。这与软件工程中提倡的低耦合、高内聚原则一致,以下是具体原因和替代方案: --- ### 一、为什么不推荐? 1. **破坏封装性** - 全局变量可在任何位置被修改,导致程序状态难以追踪 - 增加之间的隐式依赖关系(如:`extern MyGlobalVar`) 2. **线程安全隐患** - Qt多线程操作全局变量时需频繁加锁(`QMutex`),增加复杂度 - 示例问题:`QTimer`回调与主线程同时修改同一全局变量 3. **测试困难** - 单元测试时难以隔离全局状态 - 测试用例之间可能产生意外耦合 4. **架构劣化** - 违背MVC/MVVM等设计模式原则 - 导致代码难以扩展和维护 --- ### 二、Qt推荐替代方案 #### 1. 信号与槽机制(首选方案) ```cpp // 数据拥有者 class DataHolder : public QObject { Q_OBJECT public: void updateData(int value) { m_data = value; emit dataChanged(value); // 触发信号 } signals: void dataChanged(int newValue); private: int m_data; }; // 数据使用 class Consumer : public QObject { Q_OBJECT public slots: void handleDataChange(int value) { qDebug() << "Received new value:" << value; } }; ``` #### 2. 单例模式(需谨慎使用) ```cpp class AppConfig : public QObject { Q_OBJECT public: static AppConfig& instance() { static AppConfig instance; return instance; } QString theme() const { return m_theme; } void setTheme(const QString &theme) { if (m_theme != theme) { m_theme = theme; emit themeChanged(theme); } } signals: void themeChanged(QString); private: explicit AppConfig(QObject *parent = nullptr) : QObject(parent) {} QString m_theme = "light"; }; ``` #### 3. 依赖注入 ```cpp // 通过构造函数传递共享对象 class UserInterface : public QWidget { public: UserInterface(DataModel &model, QWidget *parent = nullptr) : QWidget(parent), m_model(model) {} private: DataModel &m_model; // 引用共享模型 }; ``` #### 4. 使用模型/视图架构 ```cpp // 创建全局共享的QAbstractItemModel派生 class GlobalModel : public QAbstractTableModel { // 实现标准模型接口 }; // 在QApplication初始化时创建 QSharedPointer<GlobalModel> model(new GlobalModel); // 任何视图都可以绑定该模型 QTableView view; view.setModel(model.data()); ``` --- ### 三、特殊情况处理 若必须使用似全局的访问,推荐: ```cpp // 在QApplication子中封装全局数据 class MyApp : public QApplication { Q_OBJECT public: MyApp(int &argc, char **argv) : QApplication(argc, argv) {} // 通过属性系统访问 Q_PROPERTY(QString globalConfig READ globalConfig WRITE setGlobalConfig NOTIFY globalConfigChanged) // ... 属性实现 }; ``` --- ### 四、Qt核心设计哲学 1. **对象树机制** - 通过父子对象关系自动管理内存 - 使用`QObject::findChild`查找对象 2. **上下文属性(QML交互)** ```cpp // 设置全局可访问属性 qmlEngine->rootContext()->setContextProperty("appSettings", &settings); ``` 3. **持久化方案** - 使用`QSettings`替代全局变量存储配置 - 数据库访问通过统一的数据管理层 --- ### 五、性能考量 - 信号/槽比全局变量访问稍慢(约纳秒级差异) - 实际项目中这点性能损耗可忽略不计 - 编译器会优化空信号连接(Qt5开始支持) --- **结论**:Qt框架提供了丰富的机制(信号槽、模型/视图、上下文属性等)来替代全局变量。遵循这些设计模式能显著提升代码质量,建议仅在极少数特殊场景(如底层性能优化)考虑有限制的全局访问方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值