Qt d指针简单实现及解析--威力加强版
2012-04-18 17:01
453 查看
学习d指针,怎能不研究一下q指针呢,说句实话,看完q指针后,你才会发现,它的理解其实比q指针还晦涩。
把代码贴上先:
代码比较多,不过都是在上篇文章基础上添加的,可以先看下简单的,再来看这篇文章。
主要修改之处体现在添加了宏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->函数的字样,会发现,这些函数(猜想)全是普通函数,,,剩下的,,,你懂了。。。。
完毕,感谢观赏。
把代码贴上先:
/*object.h*/ #ifndef _OBJECT_H_ #define _OBJECT_H_ #include <iostream> #define INVOKE_METHOD_PRIVATE(Class) Class##Private *d_func() {return reinterpret_cast<Class##Private*>(d_ptr);} #define Q_D(Class) Class##Private* d = d_func(); #define INVOKE_METHOD_PUBLIC(Class) Class *q_func() {return static_cast<Class*>(q_ptr);} #define Q_Q(Class) Class* q = q_func(); using namespace std; class ObjectPrivate; class Object; class ObjectData { public: virtual ~ObjectData() = 0; Object* q_ptr;//公共类的指针 }; class Object { INVOKE_METHOD_PRIVATE(Object) public: Object(); ~Object(); Object(ObjectPrivate &dd); protected: ObjectData* d_ptr;//私有类的指针 //ObjectPrivate* d_ptr; public: int m_nDescription; }; #endif
/*object_p.h*/ #ifndef _OBJECT_P_H_ #define _OBJECT_P_H_ #include "object.h" class ObjectPrivate : public ObjectData { INVOKE_METHOD_PUBLIC(Object) public: ObjectPrivate(); virtual ~ObjectPrivate(); //Object* q_ptr; }; #endif
/*object.cpp*/ #include "object.h" #include "object_p.h" ObjectData::~ObjectData() { } ObjectPrivate::ObjectPrivate() { q_ptr = 0; }; ObjectPrivate::~ObjectPrivate() { }; Object::Object() :d_ptr(new ObjectPrivate) { d_ptr->q_ptr = this;//初始化公共类指针,如果本类被直接调用(使用) m_nDescription = 5000;//本类的标签 } Object::Object(ObjectPrivate &dd) :d_ptr(&dd) { d_ptr->q_ptr = this;//初始化公共类指针,子类被调用的同时,本方法被调用 m_nDescription = 5000; } Object::~Object() { }
/*widget.h*/ #ifndef _WIDGET_H_ #define _WIDGET_H_ #include "object.h" class WidgetPrivate; /*enumeration*/ enum _state//模拟QWidget的状态 { OPEN = 0, CLOSE, UNKNOWN, }; /*Widget's state data*/ class WidgetData { public: _state m_state; }; class Widget : Object { INVOKE_METHOD_PRIVATE(Widget) public: Widget(); ~Widget(); /*functions*/ void setWidth(int); void setHeight(int); int getWidth(); int getheight(); int getSUM(void); long getProduct(void); int getDecrease(void); void setState(_state s); _state getState(void); WidgetData* data;//本类的状态数据封装类 void display();//用于测试在WidgetPrivate类中使用q_ptr调用 public: int m_nDescription;//本类的标签 }; #endif
/*widget_p.h*/ #ifndef _WIDGET_P_H_ #define _WIDGET_P_H_ #include "object_p.h" #include "widget.h" class WidgetPrivate : public ObjectPrivate { INVOKE_METHOD_PUBLIC(Widget) public: WidgetPrivate(); ~WidgetPrivate(); /*members*/ int nWidth; int nHeight; WidgetData data; /*functions*/ void init(); inline int getSUM_p(void) { Q_Q(Widget) if(q == 0)//测试q指针 { cout<<"NULL"<<endl;; } std::cout<<"Description :"<<q->m_nDescription<<std::endl; return nWidth+nHeight; } inline long getProduct_p(void) { return (long)(nWidth*nHeight);//this will be a problem } int getDecrease_p(void); void setState_p(_state s); _state getState_p(void); }; #endif
/*widget.cpp*/ #include "widget.h" #include "widget_p.h" Widget::Widget() :Object(*new WidgetPrivate) { m_nDescription = 100; Q_D(Widget) d->init(); } Widget::~Widget() { data = 0; } WidgetPrivate::WidgetPrivate() { } WidgetPrivate::~WidgetPrivate() { } void WidgetPrivate::init() { Q_Q(Widget) q->data = &data; q->display(); } int WidgetPrivate::getDecrease_p(void) { return nWidth - nHeight; } //WidgetPrivate自己设置状态 void WidgetPrivate::setState_p(_state s) { data.m_state = s; } //WidgetPrivate自己取得状态 _state WidgetPrivate::getState_p(void) { return data.m_state; } void Widget::setWidth(int n) { Q_D(Widget) d->nWidth = n; } void Widget::setHeight(int n) { Q_D(Widget) d->nHeight = n; } int Widget::getWidth() { Q_D(Widget) return d->nWidth; } int Widget::getheight() { Q_D(Widget) return d->nHeight; } int Widget::getSUM(void) { Q_D(Widget) return d->getSUM_p(); } long Widget::getProduct(void) { Q_D(Widget) return d->getProduct_p(); } int Widget::getDecrease(void) { Q_D(Widget) return d->getDecrease_p(); } //Widget自己设置状态 void Widget::setState(_state s) { data->m_state = s; } //Widget自己取得状态 _state Widget::getState(void) { return data->m_state; } void Widget::display() { cout<<"Widget::display()"<<endl; }
/*main.cpp*/ #include "widget.h" int main() { Widget w; w.setWidth(6); w.setHeight(7); std::cout<<"width : "<<w.getWidth()<<std::endl; std::cout<<"height : "<<w.getheight()<<std::endl; cout<<"getSUM :"<<w.getSUM()<<std::endl; _state s = OPEN; w.setState(s); cout<<"state : "<<static_cast<int>(w.getState())<<endl; system("pause"); return 0; }
代码比较多,不过都是在上篇文章基础上添加的,可以先看下简单的,再来看这篇文章。
主要修改之处体现在添加了宏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->函数的字样,会发现,这些函数(猜想)全是普通函数,,,剩下的,,,你懂了。。。。
完毕,感谢观赏。
相关文章推荐
- Qt d指针简单实现及解析--威力加强版
- Qt d指针简单实现及解析
- Qt d指针简单实现及解析
- 解析智能指针底层简单实现
- Qt实现SAX2方式解析XML文件(简单有效、老少皆宜,200MB大小4-7层的XML解析只需要30s)
- Dubbo 原理解析-Dubbo 内核实现之 SPI 简单介绍
- Qt之美(一):D指针/私有实现
- C++中智能指针的工作原理和简单实现
- Python实现简单HTML表格解析的方法
- d指针在Qt上的应用及实现(d指针能实现二进制兼容)
- C++ 引用计数技术及智能指针的简单实现
- 一个简单的Android客户端从服务器端获取json数据并解析的实现代码
- Qt用qml实现简单的粒子效果
- C++智能指针的简单实现
- Dubbo原理解析-注册中心之基于dubbo协议的简单注册中心实现
- c语言入门:用qt实现简单IDE
- Java实现Qt的SIGNAL-SLOT机制(保存到Map中,从而将它们关联起来,收到信号进行解析,最后反射调用)
- C++ 智能指针的简单实现
- Skinned Mesh 原理解析和一个最简单的实现示例
- 原创 Qt之美(一):D指针/私有实现 收藏 此文于2010-12-01被推荐到CSDN首页 如何被推荐? The English version is available at: http://xizhizhu.blogspot.com/2010/