Qt_log2000_信号与槽中的connect函数之深入part1

来源:互联网 发布:社会经济发展数据库 编辑:程序博客网 时间:2024/06/10 20:31

Qt学习记录5

Qt; C++ 11; Qt父子窗体; Qt父子窗体间信息传递; Qt信号与槽; 函数指针;

学习Qt将近2个月了,现在对学习所得进行记录。本文是log2000计划的一部分

实验环境:
Qt5.8.0 支持C++ 11
ubuntu 14.04 64bit


在记录connect函数之前,现需要一些预备知识。

①成员函数指针

首先看一段代码

#include <iostream>using namespace std;class Person {    public:        void sayHello(){            cout<<"你好"<<"  ";            printf("%d\n",&Person::sayHello);        }        virtual void sayName(){            cout<<"我没有名字"<<"  ";            printf("%d\n",&Person::sayName);        }};class Child : public Person {    public:    void sayHello(){        cout<<"你好"<<"  ";        printf("%d\n",&Child::sayHello);    }    virtual void sayName(){        cout<<"我是小明"<<"  ";        printf("%d\n",&Child::sayName);    }};typedef void (*FunctionPointer)();typedef void (Person::*PersonMemberFunctionPointer)();typedef void (Child::*ChildMemberFunctionPointer)();void runfuncName(Person * obj, void (Person::*func)() ){//PersonMemberFunctionPointer func    (obj ->* func)();}int main(int argc, char *argv[]){    Person someone;    Child xiaoming;    PersonMemberFunctionPointer pp;    pp = &Person::sayHello;    (someone .* pp)();    //等价于 (&someone ->* pp)();    //也等价于 someone.sayHello();    (xiaoming.*pp)();    //pp=&Child::sayHello;(不能运行,需要强制转换)    ChildMemberFunctionPointer cp = &Child::sayHello;    (xiaoming.*cp)();    runfuncName(&xiaoming,pp);    PersonMemberFunctionPointer pp2 = &Person::sayName;    (someone.*pp2)();    (xiaoming.*pp2)();//必须是公开继承,才有权限    //pp2 = &Child::sayName;(不能运行,需要强制转换)    return 0;}

程序输出:

Starting /home/pc/build-1-Desktop_Qt_5_8_0_GCC_64bit-Debug/1...你好  4197112 【作者注:someone.sayHello();数字为输出的地址】你好  4197112 【作者注:虽然是xiaoming,但同样调用的是someone.sayHello();数字为输出的地址】你好  4197348 【作者注:xiaoming.sayHello();数字为输出的地址】你好  4197112 【作者注:虽然是xiaoming,但同样调用的是someone.sayHello();数字为输出的地址】我没有名字  1 【作者注:someone.sayName();数字为输出的地址】我是小明  1   【作者注:xiaoming.sayName();数字为输出的地址】/home/pc/build-1-Desktop_Qt_5_8_0_GCC_64bit-Debug/1 exited with code 0

分析上面的代码,其中

  • typedef void (*FunctionPointer)();是普通函数指针,typedef void (Person::*PersonMemberFunctionPointer)();是成员函数指针
  • 函数runfuncName中如果不适用typedef,那么必须PersonMemberFunctionPointer func这么定义,可是由于使用了typedef,只需要Person::*func,而void (Person::*func)()为参数形式调用时的用法。
  • 函数runfuncName中看出,通过函数调用时要通过“对象(obj->* func)()”这么调用。成员函数指针之所以要通过对象调用是因为形参中默认多了this指针,也就是成员函数sayHello的形参中
  • 因为sayHello不是虚函数,所以(xiaoming.*pp)();是调用的Person类而不是Child类的sayHello。而runfuncName(&xiaoming,pp);也是因为sayHello不是虚函数,故调用的仍是Person类。

②成员变量指针

看一段代码

#include <iostream>using namespace std;class A{  public:    int x;};void func(A obj, int A::* p){//MemberPointer p    cout<<obj.*p<<endl;}void func2(A * obj, int A::* p){    cout<<obj->*p<<endl;}template   <class   T>void func3(T * obj, int T::* p){    cout<<obj->*p<<endl;}typedef int A::* MemberPointer;int main(int argc, char *argv[]){    MemberPointer pV;    //成员变量指针的定义    //等价于int A::* pV;    pV = &A::x ;    A a;    a .* pV=1;//等价于a.x=1;    cout << &a ->* pV << endl;    func(a,pV);    func2(&a,pV);    func3(&a,pV);    return 0;}

程序输出:

Starting /home/pc/build-2-Desktop_Qt_5_8_0_GCC_64bit-Debug/2...1 【作者注:a.x=11 【作者注:a.x=11 【作者注:a.x=11 【作者注:a.x=1】/home/pc/build-2-Desktop_Qt_5_8_0_GCC_64bit-Debug/2 exited with code 0

分析上面的代码,其中

  • void func(A obj, int A::* p)是成员变量指针普通调用法,看详细定义:cout<<obj.*p<<endl;看到‘.’了吧
  • void func2(A * obj, int A::* p)是指针调用法,看详细定义:cout<<obj->*p<<endl;看到‘->’了吧
  • template <class T>是模板调用法,非本次讨论重点
  • typedef int A::* MemberPointer;定义类型名(将定义的变量名改为类型名)
  • pV = &A::x ;没有默认传this指针,这个pV为任何A类对象从这个对象首地址到这个成员变量x的偏移量

③函数指针

看一段代码

#include <iostream>using namespace std;void hello(){    cout<<"abc"<<endl;}int abc(int x){    return x+1;}typedef void (*pHello)();int main(int argc, char *argv[]){    //1    int (*fAbc)(int);//int (*fAbc)(int axc);    fAbc=&abc;    cout<<(*fAbc)(1)<<endl;    //2    typedef int (*pF)(int);//should be with that pHello line above, but for the sake or understanding, put it here.    pF y;    y=&abc;    //pF y=&abc; is also ok    cout<<(*y)(1)<<endl;    //3    void (*pf)(void);    pf = &hello;    (*pf)();    /*pf=hello      pf()*/is also ok    //4    pHello p = &hello;    (*p)();    return 0;}

程序输出:

Starting /home/pc/build-3-Desktop_Qt_5_8_0_GCC_64bit-Debug/3...22abcabc/home/pc/build-3-Desktop_Qt_5_8_0_GCC_64bit-Debug/3 exited with code 0

分析上面的代码,其中

  • //1中对于函数指针的声明为int (*fAbc)(int);,后面括号中的int也可以写成int xxx,即int (*fAbc)(int axc);
  • //1中定义了一个指针变量fAbc,它是一个指向某种函数的指针,这种函数参数是一个int型,返回值是int类型。
  • //1中对应的赋值方式为fAbc=&abc;
  • //1中对应的的调用方式为(*fAbc)(1);
  • //2中对于函数指针的声明为typedef int (*pF)(int);虽然与//1很相似,但//2的优点是更加直观方便
  • //2中定义了一种pF的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回int类型
  • //2中对应的赋值方式为pF y=&abc;
  • //中对应的调用方式为(*y)(1)
  • //3和//4都大同小异

visitor tracker
访客追踪插件


0 0