基于DirectUI 的SCW- C++私有类实现要点及心得
2015.03
在设计 SCW 的过程中。不断了解新知识,作为一个C++ 初学者,新的知识尤如甘露。尤其在学习过程中,看到别人好的经验与方法,就像发现了新大陆一样。SCW 框架虽然还在构建中,还没到 DirectUI 那一步,但学习与开发的过程,充满惊喜。
这两天在重构SCW ,这已经是第三稿了。虽然我的基础浅薄,知识不深,但我懂得一个道理。如果想弄个好点的SCW 界面开发工具出来。没有好的框架,后面实现所谓的DirectUI 都是虚的。要想做个理想一点的框架,就得学好基础知识。
因此,这几天,我重新去回个头来看看C++ 类结构方面的知识,仔细,认真理解C++ 对内存与指针的管理。你网上漫游中,终于找到了一些好的知识点。其中C++ 类中通过私有类来实现类的兼容与扩展,提高类的框架适应度,封装类的思路的经验。就是好的收获。
私有类的实现,在QT 中被普遍使用。QT 中的 Q_D, Q_Q, 就是对私有类的引用接口。通过二天的了解与实操,现在将私有类的一些认识总结出来。
在第一次接触到这个概念时,我同样也有以下几下疑问:
1. 什么是私有类的实现?
2. 如何来实现?
3. 私有类有什么必要性?为什么要引用私有类这种概念或方法
4. 有什么弊端?
通过学习,加上自己动手实践,以上的问题,被我一一解决或理解。而且,也决定,在做 DirectUI 的SCW 界面框架时,用上这个好方法。
1. 先说说什么是私有类的实现
简言之,就是在一个类ClassA 中,通过私有的另一个类ClassB ,来实现大部分的功能。并且ClassB 只为 ClassA 服务,也就是说,其他的类,是不能直接访问 ClassB 的,这就是 ClassA 的私有类。
初看起来,好像没有必要,因为设计一个类,就是想达到某一任务或目的。直接用这个类来完成就行了。为什么还要通过另外一个类来实现呢?这就引出了第二个问题,用私有类有什么好处?
我们需要展开来说说私有类的实现,才能更好地理解这种实现的好处:
ClassA 引用私有类ClassB, 不是简单地想通过 ClassB 来实现其功能而已。如果仅是这样,真没有必要。直接用ClassA 不更好?事件不是这样简单。ClassA 之所以使用私有类,有结构上的优势与必要。先来看看他的实现:
概括总结一下私有类的实现重点:
在主类.h 头文件中声明主类主体结构。同时 声明主类需要引用到的私有类的友元关系 (即 friend class classB )并 声明一个访问私有类的成员变量 classB b 或接口;
2. 不需要在主类.h 头文件中include 包含私有类头文件。也不要在工程任何一个.h 头文件中include 包含私有类的.h 头文件。 这是重点。
在主类的实现源文件(.cpp) 中包含主类.h 头文件和私有类.h 头文件。同时在源文件中实现主类与私有类的功能。(也可以分别用几个.cpp 来分别实现主类和私有类,代码写在哪都不不影响。)
举例实现如下:
文件class_a.h
class ClassA { protected: friend class classB; // 声明友元关系 public: classB b; // 私有类访问入口 void func() …… }
再在另一个头文件class_b.h 中声明 classB. 的类的结构主体。(具体就不书写了)
重点来了,在实现 classA 的代码文件classA.cpp 中。同时包含 class_a.h, class_b.h.
这样,classB 类以及classB.h 文件就实现了私有性, class_b.h 文件只在 classA.cpp 文件中被引用。在工程中的其他任何地方,都不需要引用class_b.h 头文件。
这个时候,可以设想一下,任意修改 classB 类的结构即修改class_b.h 头文件,都不会对工程中的其他模块有影响。甚至也不会影响 class_a.h 文件。
至于哪些功能放在 classA 来实现,哪些功能要 classB 来实现,这就是自己个人的设计思路与安排了。你甚至完成不需要 classA 来实现任何具体内容,仅作为一个接口性的类也行。
再举个小例子:
classA 想实现 x, y 值的读取与写入。classA 只需这样来实现.
class classA { int X(int value = 0, boo IsWirte = false) { if (IsWrite) // 写入标志 b->x = value; // 假设 b 是 classA的私有类对象 return b->x; }; // y 的实现同上 }
A 简化了要声明成员变量x ,一个函数就解决了读写。当然,这只是一个简单示例,更多的实现需要个人去挖掘。
如果看到这,你能想到了点些什么,说明你开始理解私有类的必要性了。
为什么要使用这样的结构?这正是私有类存在的核心。也正是私有类的好处好处与必要性所在。
2. 使用私有类的好处。
通上上面的简单的说明,我们可以初步发现,私有类的几个好处。
可以简化主类的结构。
可以封装主类的功能。
主类功能的扩展在私有类中实现,不会影响主类的头文件结构。比如声明中间变量,添加一些中间处理函数等。
大大提升了主类的兼容性与扩展性。
可以达到隐藏设计思路的目的(这个仅作参考)
用以上小例子来说明一下:
类 ClassA, 我们需要再添加一个功能,在设置 X 的值时,需要检测一下X 的大小,并且限定在 >0 并且 <N 。当然,我们可以直接在 classA 的结构中添加一个常量N ,并修改 X() 函数代码达到目的 。但是,这样 classA.h 的结构被改动,头文件会被重新编译,工程中引用到classA 的其他文件也会被重新编译,如果这个classA 是深底层性的基类,而且你的工程很大,文件很多的话,可想而知。
如果我们仅是修改 classB 的头文件,和.cpp 代码文件,这种情况就不会发生。虽然都是同样的目的,同样的修改,但是产生的结果大不一样。
实际情况会更复杂。我们只是用一个简单例子来引申一下。实际应用中,我们可能会为完成一些新的任务,需要添加新的变量和处理函数。但是,如果这些添加都是在 classB 中完成,classA 的结构一点都不需要动。这样保证了classA 的兼容性,同时也达到了扩展 classA 的功能的目的。同时减少了对头文件的依赖。
具体应用场景自己去设想一下。如果 classA 需要在更新中不断添加新功能,新变量。你甚至不需要改动 classA 的任何结构,而只是 直接调用 classA 的私有成员来实现(当然,不建议这样实现)。例如 A.PrivateObject()->newfunc(). 或 A.PrivateObject()->Width = 100; 诸如此类的实现可能。
如果 classA 是对外发布的 dll 文件中的公共引用类,classA 每一次结构的修改,都会对被 dll 版本的更新带来不兼容的可能性。 设计科学的私有类,可以达到优化程序或库文件的二进制代码的兼容性。
3. 弊端。
相对于优点来说,使用私有类的弊端,可以说一点都不是个事。
代码量增多。因为功能实现了转接,需在在主类添加一些转接性的代码,同时也增加了工作量。
代码不再清晰明。以前直接处理的功能不再直接。对后来的开发者来说,需要花更多的时间去熟悉了解。
尤其在修复BUG 时,因为不再直接明了的流程,需要重新回塑设计思路。
如果设计不当,私有类反而会带来麻烦。让程序结构显得混乱。
4. 要点:
合理使用类的私有类实现方法。可以达到以上说的好处。
只对重要的类才进行私有类的设计 。不要什么类都实现私有类。
要有一套统一的实现方法,比如设计一些方便的宏,规范统一的转接口标准等。
要想更好地理解私有类,建议去深入QT 中类的实现。并自己动手设计案例来完成一些测试。
以前在刚学习类的概念时,我就认为,类已经是一种很好的封装与兼容了。
但 是,我们在设计好一个类之后,会因为知识的积累或需求的增加,也可能因为客户的需求或功能的丰富,经常性地去完善一个类。在没有私有类这个概念的时候,我 们一般都是直接在类的原始结构上添加新成员变量或成员函数来完成这些修改。如果引用私有类的概念,主类的原始结构就不需要过多的修改甚至不作任何修改。类 的封装与兼容得到了进一步的升华!
我已经在我的 SCW 界面库中采用了私有类。并测试完善了私有类的应用。
SCW 的个人想法,请参阅: 基于DirectUI的SC设计规划的个人构想与目标
SCW 的DirectUI 界面设计交流,请加 QQ 群: 177312461 或个人QQ: 48018276