条款15: 在资源管理类中提供对原始资源的访问
(Provide access to raw resources in resource-managing classes.)
内容:
使用资源管理类使我们在一定程度上能够摆脱对原始资源的访问而造成的诸多风险,但在有有些情况下,当
我们需要直接对资源进行访问操作时候,管理类这样的封装无疑给我们开发带来了不便,我们来举个例子来说明
这种情况.
现在我们有个图片资源工厂方法createImageResource();现在我们用auto_ptr对其进行管理:
auto_ptr<Image> sptrImageRes(createImageResource);
而现在我们要对这张图片进行去色处理,处理函数为int decolourize(Image* psourceImage)我们这样调用
它:
decolourize(sptrImageRes);//当然不对啦,类型不匹配嘛
这里我们就需要这个图片管理类来提供一个接口,此接口能够提供实现我们直接访问资源功能.幸好auto_ptr
提供了get函数来执行显式转换,即返回管理对象的内部原始的资源指针.
decolourize(sptrImageRes.get());//get方法就是其提供的接口函数
一般来说,管理资源类都提供用户对原始资源的访问接口,通常通过显式转换或者隐式转换达到目的.上面举
的例子是通过函数接口执行显式转换来获得原始的资源指针,我们也可以通过重载操作符->或者*来执行隐式转换
获得原始资源指针,例如tr1::shared_ptr与auto_ptr都重载了operator->与operator*函数实现,我们就可以通过
它们直接访问image提供的接口操作:
class Image{
public:
bool loadDataFromFile(const string& filename);
void blacklize();
void whiteBalance();
...
};
//test.cpp
sptrImageRes->loadDataFromFile("shania twain.jpg");
sptrImageRes->blacklisze();
(*sptrImage).whiteBalance();
而在有些时候我们觉得我们需要直接对原始资源对象进行操作而不是对管理类进行操作(这样做感觉起来更
加的贴近事实的感觉,是不是?呵呵),这个时候我们通常通过隐式转换函数来实现,这样就会更直观,我们可以这样
写:
class Image{
public:
operator HANDLE()const{
return imageHandle_;
}
...
private:
HANDLE imageHandle_;
};
那么我们就可以很轻松的写下如下代码:
Image theImage;
HANDLE handle = theImage; //OK! perfect! hehe
书上有这么一段话:是否该提供一个显式转换函数(例如get成员函数)将RAII class转换为其底部资源,或是
应该提供隐式转换,答案主要取决于RAII class被执行的特定工作以及它被使用情况.最佳设计是坚持忠告:"让接
口容易被正确使用,不易被误用".通常显式转换函数如get是比较受欢迎的路子,因为它将"非故意之类型转换"的可能性最小
化了.然而有时候,隐式类型转换所带来的"自然用法"也会引发天平倾斜.
请记住:
■ APIs往往要求访问原始资源(raw resources),所以每一个RAII class应该提供一个"取得其所管理之资源"的办
法.
■ 对原始资源的访问可能经由显式转换或隐式转换.一般而言显式转换比较安全,但隐式转换对客户比较方便.