qt 元对象系统及属性系统

Qt元对象系统(QMetaObject)

Qt 的元对象系统叫 Meta-Object-System,提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI(RTTI的实现耗费了很大的时间和存储空间,这就会降低程序的性能),我们也能动态获取类型信息。

元对象实质上是对类的描述

但是,元对象是基于三个条件的:

 1、该类必须继承自QObject类

 2、必须在类的私有声明区声明Q_OBJECT宏(在类定义的时候,如果没有指定public,

则默认为private,用来启用元对象功能,比如动态属性、信号和槽)。

 3、 元对象编译器Meta-Object Compiler(moc)为 QObject的子类实现元对象

特性提供必要的代码。

有了元对象系统后,我们就可以使用Qt的信号和槽了。

moc(Meta-Object Compiler)元对象预编译器。

moc读取一个c++头文件。如果它找到包含Q_OBJECT宏的一个或多个类声明,它会生成一个包含这些类的元对象代码的c++源文件,并且以moc_作为前缀。

信号和槽机制、运行时类型信息和动态属性系统需要元对象代码。

由moc生成的c++源文件必须编译并与类的实现联系起来。通常,moc不是手工调用的,而是由构建系统自动调用的。

获取类关联的元对象的函数是:metaObject

QMetaObject  *mtobj = QObject::metaObject()

如:

QPushButton *btn=new QPushButton();

const QMetaObject *metaPtr=btn->metaObject();        //获取元对象指针

常用的函数:

(1)函数QMetaObject::className():该函数运行时返回类名称的字符串

(2)函数QObjetc::inhetits()。可以判断一个对象是不是继承自某个类的实例。顶层的父类是QObject ;

(3)函数QMetaObject::superClass()。用来返回该元对象所描述类的父类的元对象,通过父类的元对象可以获取父类的一些元数据;

(4)函数qobject_cast(): 对于Object及其子类对象,可以使用函数qobject_cast()进行动态类型转换,此处可以理解为c++中的强制类型转换

属性系统Q_PROPERTY

在QObject的子类中,使用宏Q_PROPERTY定义属性

Q_PROPERTY(type name

           (READ getFunction [WRITE setFunction] |

            MEMBER memberName [(READ getFunction | WRITE setFunction)])

           [RESET resetFunction]

           [NOTIFY notifySignal]

           [REVISION int]

           [DESIGNABLE bool]

           [SCRIPTABLE bool]

           [STORED bool]

           [USER bool]

           [CONSTANT]

           [FINAL])

Q_PROPERTY()宏定义一个返回值类型为type,名称为name的属性。属性的类型可以是QVarient支持的任何类型( C++标准类型、类名、结构体、枚举等),也可以用户自定义类型。

READ:用于读取属性值。

WRITE:写访问器函数是可选的。用于设置属性值。它必须返回void,并且必须只接受一个参数,要么是属性的类型,要么是指向该类型的指针或引用。

MEMBER:如果未指定读取访问器函数,则需要成员变量关联。这使得给定的成员变量可读写,而无需创建读写访问器函数。使用MEMBER可以替代READWRITE

RESET:复位功能是可选的。它用于将属性设置回其特定于上下文的默认值。

NOTIFY通知信号是可选的。如果已定义,它应该指定该类中的一个现有信号,该信号在属性值更改时发出

定义属性:

头文件:

#ifndef COLORMAKER_H

#define COLORMAKER_H

#include <QObject>



class CTest

{

public:

    CTest(){}

    int nAge;

    QString strName;

};



Q_DECLARE_METATYPE(CTest)



class ColorMaker : public QObject

{

    Q_OBJECT

public:

    explicit ColorMaker(QObject *parent = nullptr);

    ~ColorMaker();



    Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);

    Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定义的类



    int getvalue() const;

    void setvalue(const int& value);



    CTest gettest() const;

    void settest(const CTest& test);



signals:

    void valueChanged(int value);

    void testChanged(CTest test);

private:

    int m_value;

    CTest m_test;

};



#endif // COLORMAKER_H

源文件

#include "ColorMaker.h"



ColorMaker::ColorMaker(QObject *parent)

{

}

ColorMaker::~ColorMaker()

{



}

int ColorMaker::getvalue() const

{

    return m_value;

}

void ColorMaker::setvalue(const int &value)

{

    m_value = value;

    emit valueChanged(m_value);

}

CTest ColorMaker::gettest() const

{

    return m_test;

}

void ColorMaker::settest(const CTest &test)

{

    m_test = test;

    emit testChanged(m_test);

}

使用属性:

属性的读写既可以使用各个属性自己的读写函数,也可以使用属性通用的函数:setProperty() 写属性,property() 读属性,都是通过属性的名称来寻找特定属性实现读写。

bool setProperty(const char *name, const QVariant &value);

QVariant property(const char *name) const;

setProperty() 第一个参数是普通字符串,就是属性的名称,第二个参数是属性的数值。QVariant 是 Qt 定义的通用变量类型,标准 C++ 的类型和 Qt 自己的数值类型都可以自动转为 QVariant 类的对象。

int propertyCount() const; 通过元对象获取属性的个数

QMetaProperty property(int index) const; 获取属性

QMetaProperty const char *name() const; 获取属性名

例子:

#ifndef WIDGET_H

#define WIDGET_H



#include <QWidget>

#include "ColorMaker.h"



QT_BEGIN_NAMESPACE

namespace Ui { class Widget; }

QT_END_NAMESPACE



class Widget : public QWidget

{

    Q_OBJECT



public:

    Widget(QWidget *parent = nullptr);

    ~Widget();



public slots:

    void recv(int nval);

    void recvtest(CTest test);







private:

    Ui::Widget *ui;

};

#endif // WIDGET_H





源文件

#include "widget.h"

#include "ui_widget.h"





#include <QDebug>

#include <QMetaProperty>



Widget::Widget(QWidget *parent)

    : QWidget(parent)

    , ui(new Ui::Widget)

{

    ui->setupUi(this);



    ColorMaker *cm = new ColorMaker();

    connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);

    connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);



    cm->setvalue(1);

    int value = cm->getvalue();

    cm->setProperty("value", 2);

    value = cm->property("value").toInt();



    CTest test;

    test.nAge = 2;

    test.strName = "qq";

    cm->setProperty("test",QVariant::fromValue(test));

    CTest test1 = qvariant_cast<CTest>(cm->property("test"));



   QObject *object  = cm;

   const QMetaObject *metaobject = object->metaObject();

   int ncount = metaobject->propertyCount();

   for (int i = 0; i < ncount; ++i)

   {

       QMetaProperty metaproperty = metaobject->property(i);

       const char *name = metaproperty.name();

       qDebug() << name;

       QVariant value = object->property(name);

       qDebug() << value;

   }



   CTest s;

   s.nAge = 1;

   s.strName = "hello";

   QVariant varTest;

   varTest.setValue(s);

   QVariant var = QVariant::fromValue(s);

   bool b = var.canConvert<CTest>();

   if(b)

   {

       CTest test = var.value<CTest>();

       CTest test1 = qvariant_cast<CTest>(var);

       qDebug() << test.nAge;

       qDebug() << test.strName;

   }

}



Widget::~Widget()

{

    delete ui;

}



void Widget::recv(int nval)

{

    int a = nval;

    qDebug() << a;

}



void Widget::recvtest(CTest test)

{

    qDebug() << test.nAge;

    qDebug() << test.strName;

}

作用:

  1. 属性系统提供了可以像操作普通的数据成员一样操作这些自定义属性的方法,同时也可以利用Qt的信号槽系统来监听属性值的变化。

使用场景:

  1. Q_PROPERTY用于c++类注册到qml交互上。在c++的变化发送信号,而在qml上接收信号,实现处理槽函数。这个使用于qml导出到c++类,c++类获取和设置qml的属性。
  2. 自定义qt designer 插件 在ui上可以直接看到并设置属性值、信号槽。

延伸:

Q_DECLARE_METATYPE

Q_DECLARE_METATYPE(Type)向Qt元系统注册一些非基本类型。Type可以是自定义类、结构体、枚举。一旦注册后,在Qt元系统中就可以很方便的利用这些非基本类型。

如果Type在命名空间中,Q_DECLARE_METATYPE()必须在命名空间外部。

定义:

class CTest

{

public:

    CTest(){}

    int nAge;

    QString strName;

};

//或者

//struct CTest

//{

//    int nAge;

//    QString strName;

//};

Q_DECLARE_METATYPE(CTest)

使用:

设置函数

QVariant::setValue或者 QVariant fromValue

获取函数

Value 或者 QVariant fromValue

   CTest s;

   s.nAge = 1;

   s.strName = "hello";

   QVariant varTest;

   varTest.setValue(s);

   QVariant var = QVariant::fromValue(s);

   bool b = var.canConvert<CTest>();

   if(b)

   {

       CTest test = var.value<CTest>();

       CTest test1 = qvariant_cast<CTest>(var);

       qDebug() << test.nAge;

       qDebug() << test.strName;

   }

枚举常用宏

 Q_ENUM

作用:宏Q_ENUM会向元对象系统注册一个枚举类型。

使用注意事项:

1.使用Q_ENUM之前,必须在类中先声明Q_OBJECT或Q_GADGET宏。

2.Q_ENUM(枚举类型)必须放在枚举声明之后,放在前面编译器会报错。

如注册Orientation枚举

class Widget : public QWidget

{

    Q_OBJECT

public:

    Widget(QWidget *parent = nullptr);

    ~Widget();

    enum Orientation {

        Up = 1,

        Down = 2,

        Left = 3,

        Right = 4

    };

    Q_ENUM(Orientation)  //向元对象系统注册枚举类型

public slots:

    void recv(int nval);

    void recvtest(CTest test);

private:

    Ui::Widget *ui;

};

使用静态函数QMetaEnum::fromType()来获取QMetaEnum

QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //MyEnum是当前类,Orientation是枚举的类型

    QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>();  //通过静态函数fromType获取QMetaEnum对象

    QString name = metaEnum.name();                   //枚举名称

    int count = metaEnum.keyCount();                  //枚举数量

    QString keyIndex = metaEnum.key(0);               //下标为0的key

    int valueIndex = metaEnum.value(0);               //下标为0的value

    QString Key = metaEnum.valueToKey(Widget::Left);  //通过value得到key

    int value = metaEnum.keyToValue("Left");          //通过key得到value

    qDebug() << "枚举的名称:" << name;

    qDebug() << "枚举的数量:" << QString::number(count);

    qDebug() << "index下标的key值:" << keyIndex;

    qDebug() << "index下标的Value值:" << QString::number(valueIndex);                                                                        qDebug() << "value对应的key值:" << Key;

    qDebug() << "key值对应的Vaule:" << QString::number(value);

Q_FLAG

为了解决枚举变量的组合使用,增加枚举变量间与或非计算。且运算结果还是一个QFlags包装的枚举量。一个普通的枚举类型包装成QFlags型,需要使用Q_DECLARE_FLAGS宏,在全局任意地方使用”|"操作符计算自定义的枚举量,需要使用Q_DECLARE_OPERATORS_FOR_FLAGS宏。

Q_DECLARE_FLAGS()宏

Q_DECLARE_FLAGS(Flags, Enum)宏展开为 typedef QFlags<Enum>  Flags;

QFlags<Enum>是一个模板类,其中Enum是枚举类型,QFlags用于存储枚举值的组合

Q_DECLARE_OPERATORS_FOR_FLAGS()

1.Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)赋予了Flags一个全局操作符“|”,没有这个宏语句,Flags量之间进行与操作后的结果将是一个int值,而不是Flags值。

2.Q_DECLARE_OPERATORS_FOR_FLAGS必须定义在类外。

3.Q_DECLARE_OPERATORS_FOR_FLAGS只提供了“或”操作,没有提供“与”“非”操作。

例子

#ifndef WIDGET_H

#define WIDGET_H

#include <QWidget>

#include "ColorMaker.h"

QT_BEGIN_NAMESPACE

namespace Ui { class Widget; }

QT_END_NAMESPACE

class Widget : public QWidget

{

    Q_OBJECT

public:

    Widget(QWidget *parent = nullptr);

    ~Widget();

    enum Orientation {

        Up = 1,

        Down = 2,

        Left = 4,

        Right = 8

    };

    Q_ENUM(Orientation)  //向元对象系统注册枚举类型

    Q_DECLARE_FLAGS(OrientationFlag,Orientation)

    Q_FLAG(OrientationFlag)

public slots:

    void recv(int nval);

    void recvtest(CTest test);

private:

    Ui::Widget *ui;

};

Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)

#endif // WIDGET_H

使用

    QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>();  //通过静态函数fromType获取QMetaEnum对象

    QString name = metaEnum.name();                   //枚举名称

    int count = metaEnum.keyCount();                  //枚举数量

    QString keyIndex = metaEnum.key(0);               //下标为0的key

    int valueIndex = metaEnum.value(0);               //下标为0的value

    QString Key = metaEnum.valueToKey(Widget::Left);  //通过value得到key

    int value = metaEnum.keyToValue("Left");          //通过key得到value

    QString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right); //通过value得到key

    int value2 = metaEnum.keysToValue("Up | Down");

    qDebug() << "枚举的名称:" << name;

    qDebug() << "枚举的数量:" << QString::number(count);

    qDebug() << "index下标的key值:" << keyIndex;  //Up

    qDebug() << "index下标的Value值:" << QString::number(valueIndex);  //1

    qDebug() << "value对应的key值:" << Key; //Left

    qDebug() << "value对应的key值:" << Key2; //Left|Right

    qDebug() <<"key值对应的Vaule:"<< QString::number(value);//4

qDebug() <<"key值对应的Vaule:"<< QString::number(value2);//3

QMetaObject::invokeMethod()

作用:使用QMetaObject::invokeMethod()调用QObject的某个注册到元对象系统中的方法。支持跨线程调用。

一般该方法是信号、或者槽函数。无论这个方法是公有的、保护的还是私有的

如果是普通函数,则需要使用Q_INVOKABLE宏把函数注册到元对象系统。

格式:

bool QMetaObjcet:invokeMethod(

QObject* obj,

const char* member,

Qt::ConnectionType type,

QGenericReturnArgument ret,

QGenericReturnArgument  vla0 = QGenericReturnArgument(0),

QGenericReturnArgument  vla1 = QGenericReturnArgument(),

QGenericReturnArgument  vla2 = QGenericReturnArgument(),

QGenericReturnArgument  vla3 = QGenericReturnArgument(),

QGenericReturnArgument  vla4 = QGenericReturnArgument(),

QGenericReturnArgument  vla5 = QGenericReturnArgument(),

QGenericReturnArgument  vla6 = QGenericReturnArgument(),

QGenericReturnArgument  vla7 = QGenericReturnArgument(),

QGenericReturnArgument  vla8 = QGenericReturnArgument(),

QGenericReturnArgument  vla9 = QGenericReturnArgument());

返回值:返回true说明调用成功;返回false,要么是因为没有你说的那个方法,要么是参数类型不匹配;

obj:被调用对象的指针;

member:方法名字   必须是信号、槽,以及Qt元对象系统能识别的类型, 如果不是信号和槽,可以使用qRegisterMetaType()来注册数据类型。此外,使用Q_INVOKABLE来声明函数,也可以正确调用。

type:连接类型;invokeMethod为信号槽而生,你可以指定连接类型,如果被调用的对象和发起调用的线程是同一线程,那么可以使用Qt::DirectConnection、Qt::AutoConnection、Qt::QueuedConnection,如果被调用对象在另一个线程,那么建议使用Qt::QueuedConnection;

ret:接收返回值;

然后就是多达10个可以传递给被调用方法的参数;(看来信号槽的参数个数是有限制的,最好不要超过10个)

QGenericArgument和QGenericReturnArgument是内部帮助程序类,由于可以动态调用信号和槽,因此必须使用Q_ARG()和Q_RETURN_ARG()宏来封装参数

注意:此功能是线程安全的。

例子:

#ifndef COLORMAKER_H

#define COLORMAKER_H

#include <QObject>



class CTest

{

public:

    CTest(){}

    int nAge;

    QString strName;

};



Q_DECLARE_METATYPE(CTest)



class ColorMaker : public QObject

{

    Q_OBJECT

public:

    explicit ColorMaker(QObject *parent = nullptr);

    ~ColorMaker();

private slots:

    QString testslot(int n);

};



#endif // COLORMAKER_H



#include "ColorMaker.h"

ColorMaker::ColorMaker(QObject *parent)

{

}

ColorMaker::~ColorMaker()

{

}

QString ColorMaker::testslot(int n)

{

    return "q";

}

调用

#include "widget.h"

//#include "qobjectdefs.h"

#include "ui_widget.h"

#include <QDebug>

#include <QMetaProperty>

#include <QMetaObject>



Widget::Widget(QWidget *parent)

    : QWidget(parent)

    , ui(new Ui::Widget)

{

    ui->setupUi(this);

    ColorMaker *cm = new ColorMaker();

    QString retVal;

    QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);

    QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,

                 Q_RETURN_ARG(QString, retVal),

                 Q_ARG(int,1));

}



void Widget::test()

{

    int a = 1;

}

Q_INVOKABLE

作用:定义一个类的成员函数时使用Q_INVOKABLE宏来修饰,就可以让该方法被元对象系统调用(即把该函数注册到元对象系统)。

注意事项:Q_INVOKABLE宏必须放在返回类型前面。

private :

Q_INVOKABLE  QString testmd(int n);

QString ColorMaker::testmd(int n)

{

    return "md";

}

使用场景:

  1. c++和qml混用.

普通类成员函数是不能直接在qml使用。除非是声明为槽函数或者用Q_INVOKABLE声明函数.

  1. 和QMetaObject::invokeMethod()结合使用,invokeMethod函数的参数member方法如果是自定义的普通函数,需使用Q_INVOKABLE宏注册到元对象系统。

例子

class ColorMaker : public QObject

{

    Q_OBJECT

public:

    explicit ColorMaker(QObject *parent = nullptr);

    ~ColorMaker();

private :

    Q_INVOKABLE  QString testmd(int n);

};



ColorMaker *cm = new ColorMaker();

    QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,

                              Q_RETURN_ARG(QString, retVal),

                              Q_ARG(int,1));

完整代码:

#ifndef COLORMAKER_H

#define COLORMAKER_H

#include <QObject>



class CTest

{

public:

    CTest(){}

    int nAge;

    QString strName;

};



Q_DECLARE_METATYPE(CTest)



class ColorMaker : public QObject

{

    Q_OBJECT

public:

    explicit ColorMaker(QObject *parent = nullptr);

    ~ColorMaker();



    Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);

    Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定义的类



    int getvalue() const;

    void setvalue(const int& value);



    CTest gettest() const;

    void settest(const CTest& test);



signals:

    void valueChanged(int value);

    void testChanged(CTest test);

private slots:

    QString testslot(int n);

private :

    Q_INVOKABLE  QString testmd(int n);

private:

    int m_value;

    CTest m_test;

};



#endif // COLORMAKER_H





#include "ColorMaker.h"



ColorMaker::ColorMaker(QObject *parent)

{

}

ColorMaker::~ColorMaker()

{



}

int ColorMaker::getvalue() const

{

    return m_value;

}

void ColorMaker::setvalue(const int &value)

{

    m_value = value;

    emit valueChanged(m_value);

}

CTest ColorMaker::gettest() const

{

    return m_test;

}

void ColorMaker::settest(const CTest &test)

{

    m_test = test;

    emit testChanged(m_test);

}



QString ColorMaker::testslot(int n)

{

    return "q";

}



QString ColorMaker::testmd(int n)

{

    return "md";



}



#ifndef WIDGET_H

#define WIDGET_H



#include <QWidget>

#include "ColorMaker.h"



QT_BEGIN_NAMESPACE

namespace Ui { class Widget; }

QT_END_NAMESPACE



class Widget : public QWidget

{

    Q_OBJECT



public:

    Widget(QWidget *parent = nullptr);

    ~Widget();



    enum Orientation {

        Up = 1,

        Down = 2,

        Left = 4,

        Right = 8

    };

    Q_ENUM(Orientation)  //向元对象系统注册枚举类型

    Q_DECLARE_FLAGS(OrientationFlag,Orientation)

    Q_FLAG(OrientationFlag)



public slots:

    void recv(int nval);

    void recvtest(CTest test);



public slots:

    void test();



private:

    Ui::Widget *ui;

};



Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)

#endif // WIDGET_H





#include "widget.h"

//#include "qobjectdefs.h"

#include "ui_widget.h"





#include <QDebug>

#include <QMetaProperty>



#include <QMetaObject>



Widget::Widget(QWidget *parent)

    : QWidget(parent)

    , ui(new Ui::Widget)

{

    ui->setupUi(this);





    QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>();  //通过静态函数fromType获取QMetaEnum对象

    QString name = metaEnum.name();                   //枚举名称

    int count = metaEnum.keyCount();                  //枚举数量

    QString keyIndex = metaEnum.key(0);               //下标为0的key

    int valueIndex = metaEnum.value(0);               //下标为0的value

    QString Key = metaEnum.valueToKey(Widget::Left);  //通过value得到key

    int value = metaEnum.keyToValue("Left");          //通过key得到value



    QString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right);  //通过value得到key

    int value2 = metaEnum.keysToValue("Up | Down");





    qDebug() << "枚举的名称:" << name;

    qDebug() << "枚举的数量:" << QString::number(count);

    qDebug() << "index下标的key值:" << keyIndex;  //Up

    qDebug() << "index下标的Value值:" << QString::number(valueIndex);  //1

    qDebug() << "value对应的key值:" << Key; //Left

    qDebug() << "value对应的key值:" << Key2; //Left|Right

    qDebug() <<"key值对应的Vaule:"<< QString::number(value);//4

    qDebug() <<"key值对应的Vaule:"<< QString::number(value2);//3





    ColorMaker *cm = new ColorMaker();

    QObject *object  = cm;

    connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);

    connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);



    QString retVal;

    QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);

    QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,

                 Q_RETURN_ARG(QString, retVal),

                 Q_ARG(int,1));

    QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,

                              Q_RETURN_ARG(QString, retVal),

                              Q_ARG(int,1));



    cm->setvalue(1);

    int value1 = cm->getvalue();

    cm->setProperty("value", 2);

    value = cm->property("value").toInt();



    CTest test;

    test.nAge = 2;

    test.strName = "qq";

    cm->setProperty("test",QVariant::fromValue(test));

    CTest test1 = qvariant_cast<CTest>(cm->property("test"));



   const QMetaObject *metaobject = object->metaObject();

   int ncount = metaobject->propertyCount();

   for (int i = 0; i < ncount; ++i)

   {

       QMetaProperty metaproperty = metaobject->property(i);

       const char *name = metaproperty.name();

       qDebug() << name;

       QVariant value = object->property(name);

       qDebug() << value;

   }



   CTest s;

   s.nAge = 1;

   s.strName = "hello";

   QVariant varTest;

   varTest.setValue(s);

   QVariant var = QVariant::fromValue(s);

   bool b = var.canConvert<CTest>();

   if(b)

   {

       CTest test = var.value<CTest>();

       CTest test1 = qvariant_cast<CTest>(var);

       qDebug() << test.nAge;

       qDebug() << test.strName;

   }

}



Widget::~Widget()

{

    delete ui;

}



void Widget::recv(int nval)

{

    int a = nval;

    qDebug() << a;

}



void Widget::recvtest(CTest test)

{

    qDebug() << test.nAge;

    qDebug() << test.strName;

}







void Widget::test()

{

    int a = 1;



}

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值