您的位置:首页 > 编程语言 > Qt开发

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

2012-04-18 17:01 453 查看
学习d指针,怎能不研究一下q指针呢,说句实话,看完q指针后,你才会发现,它的理解其实比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->函数的字样,会发现,这些函数(猜想)全是普通函数,,,剩下的,,,你懂了。。。。

完毕,感谢观赏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: