C++箴言:最小化文件之间的编译依赖

// defining) class Date

Date today(); // as before
void clearAppointments(Date d);

  仅有声明的头文件的名字 "datefwd.h" 基于来自标准 C++ 库的头文件 <iosfwd>。<iosfwd> 包含 iostream 组件的声明,而它们相应的定义在几个不同的头文件中,包括 <sstream>,<streambuf>,<fstream> 和 <iostream>。

  <iosfwd> 在其它方面也有启发意义,而且它解释了本文所提出的建议对于模板和非模板一样有效。尽管在很多构建环境中,模板定义的典型特征是位于头文件中,但有些环境允许模板定义在非头文件中,所以为模板提供一个仅有声明的头文件依然是有意义的。<iosfwd> 就是一个这样的头文件。

  C++ 还提供了 export 关键字允许将模板声明从模板定义中分离出来。不幸的是,支持 export 的编译器非常少,而与 export 打交道的实际经验就更少了。结果是,现在就说 export 在高效 C++ 编程中扮演什么角色还为时尚早。

  像 Person 这样的使用 pimpl 惯用法的类经常被称为 Handle 类。为了避免你对这样的类实际上做什么事的好奇心,一种方法是将所有对他们的函数调用都转送给相应的实现类,而使用实现类来做真正的工作。例如,这就是两个 Person 的成员函数可以被如何实现的例子:

#include "Person.h" // we’re implementing the Person class,
// so we must #include its class definition

#include "PersonImpl.h" // we must also #include PersonImpl’s class
// definition, otherwise we couldn’t call
// its member functions; note that
// PersonImpl has exactly the same
// member functions as Person - their
// interfaces are identical

Person::Person(const std::string& name, const Date& birthday,
const Address& addr)
: pImpl(new PersonImpl(name, birthday, addr))
{}

std::string Person::name() const
{
 return pImpl->name();
}

  注意 Person 的成员函数是如何调用 PersonImpl 的成员函数的,以及 Person::name 是如何调用 PersonImpl::name 的。这很重要。使 Person 成为一个 Handle 类不需要改变 Person 要做的事情,仅仅是改变了它做事的方法。

  另一个不同于 Handle 类的候选方法是使 Person 成为一个被叫做 Interface 类的特殊种类的抽象基类。这样一个类的作用是为派生类指定一个接口。结果,它的典型特征是没有数据成员,没有构造函数,有一个虚析构函数和一组指定接口的纯虚函数。

  Interface 类类似 Java 和 .NET 中的 Interfaces,但是 C++ 并不会为 Interface 类强加那些 Java 和 .NET 为 Interfaces 强加的种种约束。例如,Java 和 .NET 都不允许 Interfaces 中有数据成员和函数实现,但是 C++ 不禁止这些事情。C++ 的巨大弹性是有用处的。在一个继承体系的所有类中非虚拟函数的实现应该相同,因此将这样的函数实现为声明它们的 Interface 类的一部分就是有意义的。
共2页 首页 上一页 [1] [2下一页 尾页>
字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z