如果您决定开始学习现代 C++ 设计,而且出身于面向对象编程(OOP)学派,那么可以从研究Loki库开始。
Loki是一个 C++ 软件库的名字,由 Andrei Alexandrescu 编写,是其著作《Modern C++ Design》(现代 C++ 设计)的一部分。
该库大量使用 C++ 模板元编程,并实现了多个常用工具:类型列表(typelist)、仿函数(functor)、单例(singleton)、智能指针、对象工厂、访问者(visitor)和多方法(multimethod)。
下面是作者设计这个库背后的动机:
- Loki 用户只需为自己想要的特性付出代价。Loki 的每个组件都可以独立于其他组件使用。
- “小即是美”——Loki 的内部依赖很少。
- “乘法效应最精彩。”——Loki 的特别关注点在于:通过组合小而抽象的行为单元(策略),获得乘法式的行为(即细粒度、专门化的设计)。
- Loki 专注于战略而非战术;专注于设计而非细枝末节;专注于架构组件而非大杂烩。
- 由于 Loki 是一个“设计的集合”,而不是“一个库的设计”,它应当对自身环境做最少的假设,并在选择了某个默认决策之处提供恰当的挂钩(hook)。
- Loki 不会迁就能力较弱的编译器。Loki 的目标是在标准 C++ 的范畴内编写可读的代码。
- 这些组件理想情况下应当小巧、易于理解和正确使用,无论单独使用还是组合使用都很实用,并能在项目中发挥巨大作用。
但在深入研究它的现代 C++ 惯用法之前,最好先掌握模板编程中的一个核心概念:基于策略的设计(policy-based design)惯用法。
基于策略设计的核心惯用法是一个类模板(称为宿主类),它接受若干类型参数,这些参数由用户选定的类型(称为策略类)实例化,每个策略类各自实现一个特定的隐式接口(称为策略),并封装宿主类实例化后行为中某个正交(或基本正交)的方面。通过提供一个宿主类,并配套每种策略的一组不同的现成实现,一个库或模块就能支持指数级数量的不同行为组合——这些组合在编译期解析,通过在宿主类模板实例化时混搭不同的策略类来选择。
下面是一个来自维基百科的小例子,演示了这个实用的惯用法:
#include
#include
template
class HelloWorld : private OutputPolicy, private LanguagePolicy
{
using OutputPolicy::print;
using LanguagePolicy::message;
public:
// Behaviour method
void run() const
{
// Two policy methods
print(message());
}
};
class OutputPolicyWriteToCout
{
protected:
template
void print(MessageType const &message) const
{
std::cout << message << std::endl;
}
};
class LanguagePolicyEnglish
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
class LanguagePolicyGerman
{
protected:
std::string message() const
{
return "Hallo Welt!";
}
};
int main()
{
/* Example 1 */
typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish> HelloWorldEnglish;
HelloWorldEnglish hello_world;
hello_world.run(); // prints "Hello, World!"
/* Example 2
* Does the same, but uses another language policy */
typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> HelloWorldGerman;
HelloWorldGerman hello_world2;
hello_world2.run(); // prints "Hallo Welt!"
}
了解基于策略的设计之后,您可以继续学习该库使用的其他惯用法:
- 多重分发器(Multiple dispatcher)
- Pimpl(指针实现惯用法)
- Printf(一种类型安全的 printf 替代方案)
- 有序静态对象创建
- 作用域守卫指针(Scope guard pointer)
- 小对象分配器(Small Object Allocator)
- 智能指针
- 编译期检查
您可以在这个有趣的资源中找到对上述惯用法的详细讲解。
总而言之,Loki 库虽不如 STL 或 Boost 那样流行,但它是一个很有趣的教学型库,可用于学习现代 C++ 设计的基本惯用法。它是掌握现代 C++ 设计的良好起点。
