Qt d指针简单实现及解析--威力加强版

学习d指针,怎能不研究一下q指针呢,说句实话,看完q指针后,你才会发现,它的理解其实比q指针还晦涩。
把代码贴上先:
[cpp]  view plain copy
  1. /*object.h*/  
  2. #ifndef _OBJECT_H_  
  3. #define _OBJECT_H_  
  4. #include <iostream>  
  5. #define INVOKE_METHOD_PRIVATE(Class) Class##Private *d_func() {return reinterpret_cast<Class##Private*>(d_ptr);}  
  6. #define Q_D(Class) Class##Private* d = d_func();  
  7. #define INVOKE_METHOD_PUBLIC(Class) Class *q_func() {return static_cast<Class*>(q_ptr);}  
  8. #define Q_Q(Class) Class* q = q_func();  
  9.   
  10. using namespace std;  
  11.   
  12. class ObjectPrivate;  
  13. class Object;  
  14.   
  15. class ObjectData  
  16. {  
  17. public:  
  18.     virtual ~ObjectData() = 0;  
  19.     Object* q_ptr;//公共类的指针  
  20. };  
  21.   
  22. class Object  
  23. {  
  24.     INVOKE_METHOD_PRIVATE(Object)  
  25. public:  
  26.     Object();  
  27.     ~Object();  
  28.       
  29.     Object(ObjectPrivate &dd);  
  30.   
  31. protected:  
  32.     ObjectData* d_ptr;//私有类的指针  
  33.     //ObjectPrivate* d_ptr;  
  34.   
  35. public:  
  36.     int m_nDescription;  
  37. };  
  38.   
  39. #endif   
[cpp]  view plain copy
  1. /*object_p.h*/  
  2. #ifndef _OBJECT_P_H_  
  3. #define _OBJECT_P_H_  
  4. #include "object.h"  
  5.   
  6. class ObjectPrivate : public ObjectData  
  7. {  
  8.     INVOKE_METHOD_PUBLIC(Object)  
  9.   
  10. public:  
  11.     ObjectPrivate();  
  12.     virtual ~ObjectPrivate();  
  13.   
  14.     //Object* q_ptr;  
  15. };  
  16.   
  17. #endif   
[cpp]  view plain copy
  1. /*object.cpp*/  
  2. #include "object.h"  
  3. #include "object_p.h"  
  4.   
  5. ObjectData::~ObjectData()  
  6. {  
  7.   
  8. }  
  9.   
  10. ObjectPrivate::ObjectPrivate()  
  11. {  
  12.     q_ptr = 0;  
  13. };  
  14.   
  15. ObjectPrivate::~ObjectPrivate()  
  16. {  
  17.   
  18. };  
  19.   
  20. Object::Object()  
  21. :d_ptr(new ObjectPrivate)  
  22. {  
  23.     d_ptr->q_ptr = this;//初始化公共类指针,如果本类被直接调用(使用)  
  24.     m_nDescription = 5000;//本类的标签  
  25. }  
  26.   
  27. Object::Object(ObjectPrivate &dd)  
  28. :d_ptr(&dd)  
  29. {  
  30.     d_ptr->q_ptr = this;//初始化公共类指针,子类被调用的同时,本方法被调用  
  31.     m_nDescription = 5000;  
  32. }  
  33.   
  34. Object::~Object()  
  35. {  
  36.   
  37. }  
[cpp]  view plain copy
  1. /*widget.h*/  
  2. #ifndef _WIDGET_H_  
  3. #define _WIDGET_H_  
  4. #include "object.h"  
  5.   
  6. class WidgetPrivate;  
  7.   
  8. /*enumeration*/  
  9. enum _state//模拟QWidget的状态  
  10. {  
  11.     OPEN = 0,  
  12.     CLOSE,  
  13.     UNKNOWN,  
  14. };  
  15.   
  16. /*Widget's state data*/  
  17. class WidgetData  
  18. {  
  19. public:  
  20.     _state m_state;  
  21. };  
  22.   
  23. class Widget : Object  
  24. {  
  25.   
  26.     INVOKE_METHOD_PRIVATE(Widget)  
  27.   
  28. public:  
  29.     Widget();  
  30.     ~Widget();  
  31.   
  32.     /*functions*/  
  33.     void setWidth(int);  
  34.     void setHeight(int);  
  35.   
  36.     int getWidth();  
  37.     int getheight();  
  38.   
  39.     int getSUM(void);  
  40.     long getProduct(void);  
  41.     int getDecrease(void);  
  42.   
  43.     void setState(_state s);  
  44.     _state getState(void);  
  45.   
  46.     WidgetData* data;//本类的状态数据封装类  
  47.   
  48.     void display();//用于测试在WidgetPrivate类中使用q_ptr调用  
  49.   
  50. public:  
  51.     int m_nDescription;//本类的标签  
  52. };  
  53.   
  54. #endif  
[cpp]  view plain copy
  1. /*widget_p.h*/  
  2. #ifndef _WIDGET_P_H_  
  3. #define _WIDGET_P_H_  
  4. #include "object_p.h"  
  5. #include "widget.h"  
  6.   
  7. class WidgetPrivate : public ObjectPrivate  
  8. {  
  9.     INVOKE_METHOD_PUBLIC(Widget)  
  10.   
  11. public:  
  12.     WidgetPrivate();  
  13.     ~WidgetPrivate();  
  14.   
  15.     /*members*/  
  16.     int nWidth;  
  17.     int nHeight;  
  18.   
  19.     WidgetData data;  
  20.   
  21.     /*functions*/  
  22.     void init();  
  23.   
  24.     inline int getSUM_p(void)  
  25.     {  
  26.         Q_Q(Widget)  
  27.         if(q == 0)//测试q指针  
  28.         {  
  29.             cout<<"NULL"<<endl;;  
  30.         }  
  31.         std::cout<<"Description :"<<q->m_nDescription<<std::endl;  
  32.         return nWidth+nHeight;  
  33.     }  
  34.   
  35.     inline long getProduct_p(void)  
  36.     {  
  37.         return (long)(nWidth*nHeight);//this will be a problem  
  38.     }  
  39.   
  40.     int getDecrease_p(void);  
  41.   
  42.     void setState_p(_state s);  
  43.     _state getState_p(void);  
  44. };  
  45.   
  46. #endif   
[cpp]  view plain copy
  1. /*widget.cpp*/  
  2. #include "widget.h"  
  3. #include "widget_p.h"  
  4.   
  5. Widget::Widget()  
  6. :Object(*new WidgetPrivate)  
  7. {  
  8.     m_nDescription = 100;  
  9.     Q_D(Widget)  
  10.     d->init();  
  11. }  
  12.   
  13. Widget::~Widget()  
  14. {  
  15.     data = 0;  
  16. }  
  17.   
  18. WidgetPrivate::WidgetPrivate()  
  19. {  
  20.   
  21. }  
  22.   
  23. WidgetPrivate::~WidgetPrivate()  
  24. {  
  25.   
  26. }  
  27.   
  28. void WidgetPrivate::init()  
  29. {  
  30.     Q_Q(Widget)  
  31.     q->data = &data;  
  32.     q->display();  
  33. }  
  34.   
  35. int WidgetPrivate::getDecrease_p(void)  
  36. {  
  37.     return nWidth - nHeight;  
  38. }  
  39.   
  40. //WidgetPrivate自己设置状态  
  41. void WidgetPrivate::setState_p(_state s)  
  42. {  
  43.     data.m_state = s;  
  44. }  
  45.   
  46. //WidgetPrivate自己取得状态  
  47. _state WidgetPrivate::getState_p(void)  
  48. {  
  49.     return data.m_state;  
  50. }  
  51.   
  52. void Widget::setWidth(int n)  
  53. {  
  54.     Q_D(Widget)  
  55.     d->nWidth = n;  
  56. }  
  57.   
  58. void Widget::setHeight(int n)   
  59. {  
  60.     Q_D(Widget)  
  61.     d->nHeight = n;  
  62. }  
  63.   
  64. int Widget::getWidth()  
  65. {  
  66.     Q_D(Widget)  
  67.     return d->nWidth;  
  68. }  
  69.   
  70. int Widget::getheight()  
  71. {  
  72.     Q_D(Widget)  
  73.     return d->nHeight;  
  74. }  
  75.   
  76. int Widget::getSUM(void)  
  77. {  
  78.     Q_D(Widget)  
  79.     return d->getSUM_p();  
  80. }  
  81.   
  82. long Widget::getProduct(void)  
  83. {  
  84.     Q_D(Widget)  
  85.     return d->getProduct_p();  
  86. }  
  87.   
  88. int Widget::getDecrease(void)  
  89. {  
  90.     Q_D(Widget)  
  91.     return d->getDecrease_p();  
  92. }  
  93.   
  94. //Widget自己设置状态  
  95. void Widget::setState(_state s)  
  96. {  
  97.     data->m_state = s;  
  98. }  
  99.   
  100. //Widget自己取得状态  
  101. _state Widget::getState(void)  
  102. {  
  103.     return data->m_state;  
  104. }  
  105.   
  106. void Widget::display()  
  107. {  
  108.     cout<<"Widget::display()"<<endl;  
  109. }  
[cpp]  view plain copy
  1. /*main.cpp*/  
  2. #include "widget.h"  
  3.   
  4. int main()  
  5. {  
  6.     Widget w;  
  7.     w.setWidth(6);  
  8.     w.setHeight(7);  
  9.     std::cout<<"width : "<<w.getWidth()<<std::endl;  
  10.     std::cout<<"height : "<<w.getheight()<<std::endl;  
  11.     cout<<"getSUM :"<<w.getSUM()<<std::endl;  
  12.     _state s = OPEN;      
  13.     w.setState(s);  
  14.     cout<<"state : "<<static_cast<int>(w.getState())<<endl;  
  15.     system("pause");  
  16.     return 0;  
  17. }  

代码比较多,不过都是在上篇文章基础上添加的,可以先看下简单的,再来看这篇文章。

主要修改之处体现在添加了宏INVOKE_METHOD_PUBLIC和Q_Q,后者调用前者提供的私有函数返回一个临时的指向公共类的指针,例如Qt的QWidget类。同时,照着Qt,添加了一个WidgetData类,它也是放一些数据的,我不太理解这个类的具体作用,暂且把它理解为盛放关于Widget状态的数据的类,它在Widget和WidgetPrivate中都有被引用,且同时指向一个对象,所以修改它的数据是同步的。

代码其实也不多,是有规律的,恐怕您看完之后会有一些疑问,在此,我把我的疑问与解答放置于此,看看您是否也是这么认为的:

  • Object,ObjectPrivate,ObjectData三者到底是什么关系?
  • INVOKE_METHOD_PUBLIC宏展开后的q_func()函数中为什么是static_cast而不是像d_func()中的reinterpret_cast?
  • 为什么q_ptr的初始化是用Objectd的this指针?而不是某个具体的类

我的理解:

对于问题一,Object其实是它的抽象基类和它自己合二为一了,它的抽象基类对应ObjectData,自己对应ObjectPrivate。在程序中打代码注释的地方,您可以看一下,把ObjectData去掉,把q_ptr移动到ObjectPrivate中,把d_ptr类型改为ObjectPrivate*.不当能成功编译,还能正确执行。不过,如果用汉语去仔细推敲的话,数据指针d_ptr怎么能是某个具体类的类型呢,失去了泛型概念。

对于问题二,static_cast的作用之一是在父子类之间进行转换,虽然从父类型指针转换到子类型指针不安全,但Qt这样做了,我理解不能

对于问题三,我感觉这才是q_ptr难于理解的关键原因,我上网查了很多资料,无一例外,所示例子中q_ptr的初始化全都是用具体的公共类的this去赋值,这很好理解,这不就是多态的概念吗:用父类指针指向一个已经初始化好的子类指针,需要的时候static_cast转换回子类类型,我感觉不出有什么问题,非常完美。可是,Qt不是这样做的,它对于q_ptr,全都是用QObject的this指针去初始化,这不会有问题吗?您可以自己写个程序测试一下,把初始化好的父类指针static_cast到子类指针,然后再用转换后的指针调用函数。你会发现,如果是普通函数被调用,指针是什么类型,就掉那个类型自己的函数,或者继承父类的函数,如果是虚函数被调用,指针是用什么类初始化的,调用的就是那个类的函数,现在您对比一下我的程序,然后再去Qt源码中查找q->函数的字样,会发现,这些函数(猜想)全是普通函数,,,剩下的,,,你懂了。。。。


完毕,感谢观赏。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值