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

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...
2
2
abc
abc
/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
访客追踪插件


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值