写在前面
本系列的上一篇已经提到了,打开QtLocation的源码工程,maps目录下组织着围绕QGeoMap这个核心类型的一个基本地图框架,其中QGeoTiledMap(继承自QGeoMap)是基于这个框架对瓦片地图的一个实现;而declarativemaps目录中的核心类型是QDeclarativeGeoMap,它对QGeoMap进行封装并注册为QML类型,并提供了地图要素(它这里称为MapItem)的渲染功能。从QDeclarativeGeoMap的名称我们可以看到QQuick1的QtDeclarative模块的烙印,但这个模块在QQuick2的时代已经过时了。
相信不少人在第一次看到Qt源码的时候很蛋疼,看到其中的Private类和诸如Q_D、Q_Q等宏时,一开始一头雾水;特别是你如果像我一样,一开始就直奔QtLocation模块的源码则会有更加深刻的体会。maps目录下几乎所有类型是私有的,这些类型的头文件末尾接着一个“_p”,很多类型还有一个同名的头文件,其末尾接着一个“_p_p”。每打开一个私有类的头文件都有一段醒目的注释:
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
这些私有类究竟有何作用呢?《The Beauty of Qt 1: D-Pointer / Private Implementation》这篇博文可以带我们一探究竟。从该博文摘取如下示例:
假如不使用D指针和Private类,那么我们可能会有如下的一个类型声明:
class MyClass
{
public:
MyClass();
~MyClass();
private:
int myVar;
};
显然,这个头文件中的私有变量myVar被其他文件#include之后是会暴露的,很多时候我们不希望引用头文件的彼方对于我们私有的成员和可能的内部实现知道得太清楚;同时这里的声明过于明确,以至于后来如果我们希望增加某些私有变量,就必须重新定义这个头文件。
于是,我们换种方式,定义一个指针d_ptr指向Private类,然后用Q_DECLARE_PRIVATE宏来定义一些辅助函数和声明友元类:
class MyClassPrivate;
class MyClass
{
public:
MyClass();
~MyClass();
private:
MyClassPrivate * const d_ptr;
Q_DECLARE_PRIVATE(MyClass);
};
简单地说