如果你阅读了 Qt 的源代码,你会看到一堆奇奇怪怪的宏,例如 Q_D,Q_Q。我们的Qt源码之旅就从理解这些宏说起。
下面先看一个C++的例子。
- class Person
- {
- public:
- Person(){}
- ~Person(){}
- string name();
- void setName(string name);
- int age();
- void setAge(int a);
- private:
- string _name;
- int _age;
- };
这是一个很普通的 C++ 类 Person,他有两个属性 name 和 age。我们试想一下,这个类要怎么去使用呢?如果你不想给我源代码,那么至少也要给我一个 dll 或者其他类似的东西,并且你要把这个头文件给我,这样我才能把它 include 到我的代码中使用。我只能使用你暴露给我的 public 的接口。按理说,private 的东西我是不应该知道的,但是现在我知道了!为什么呢?因为我会去读这个头文件,我知道了,原来在 Person 中,age 就是一个 int,name 就是一个 string。这是你不希望看到的,因为既然你把它声明成了 private 的,就是不想让我知道这些东西。那么怎么办呢?嗯,我有一个解决方案。来看下面的代码:
person.h
- class Person
- {
- public:
- Person(){}
- ~Person(){}
- string name();
- void setName(string name);
- int age();
- void setAge(int a);
- private:
- PersonPrivateData *data;
- };
persondata.cpp
- class PersonPrivateData
- {
- public:
- string name;
- int age;
- };
怎么样?在 person.h 中看不到我是怎么存储的数据了吧?嗯嗯,也许你很聪明:我还可以在 persondata.cpp 中找到那些声明啊!当然,这是C++语法规定的,我们已经左右不了——但是,我为什么非要把 cpp 文件一并给你呢?因为你使用我的类库的话完全不需要使用 cpp 文件啊。
这就是一种信息隐藏的方法。看上去很麻烦,原本很简单的对 name 和 age 的访问都不得不通过一个指针去访问它,何必呢?其实这样做是有好处的:
- 减少头文件的依赖。像这样我们把数据成员都写在 cpp 文件中,当我们需要修改数据成员的时候就只需要修改 cpp 文件。虽然都是修改,但这和修改 .h 文件是不一样的!原因在于,如果 .h 文件发生改变,编译器会重新编译所有 include 了这个 .h 文件的文件。如果你这个类相当底层,那就会花费很长时间。
- 增加类的信息封装。这意味着你根本看不到具体数据类型,必须使用 getter 和 setter 去访问。我们知道 C++ 有一个 typedef 语句,我定义一个数据类型 ABC,如果你看不到具体文件,你会知道这个 ABC 是 string 还是 int 么?
这就是 C++ 的一种设计方法,被称为 Private Class,大约就是私有类吧!更确切地说应该是私有数据类。据说,这也是 Qt 2.x 的实现方式。但是如果你去看你的 Qt SDK 代码,你是看不到这样的语句的,取而代之的则是一些我们开头所说的 Q_D 这些宏。或许你已经隐隐约约地猜到了,这些宏就是实现这个的:Private Data。
本文转自 FinderCheng 51CTO博客,原文链接: