分享
 
 
 

Guru of the Week 条款24:编译级防火墙

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

[CAT*G Translation Project GotW#22-30: Draft]

GotW #24 Compilation Firewalls

著者:Herb Sutter

翻译:CAT*G

[声明]:本文内容取自www.gotw.ca网站上的Guru of the Week栏目,其著作权归原著者本人所有。译者CAT*G在未经原著者本人同意的情况下翻译本文。本翻译内容仅供自学和参考用,请所有阅读过本文的人不要擅自转载、传播本翻译内容;下载本翻译内容的人请在阅读浏览后,立即删除其备份。译者CAT*G对违反上述两条原则的人不负任何责任。特此声明。

Revision 1.0

Guru of the Week 条款24:编译级防火墙

难度:6 / 10

(使用pimpl惯用法可以大大降低代码之间的相互依赖性,还可以减少程序的建立时间。但问题是,应该把那些东西放入pimpl对象里呢?如何才能安全的使用它呢?)

[Problem]

[问题]

在C++中,如果类定义中的任何部分被改变了(即使是私有成员),那么这个类所有的使用者代妈都必须重新编译。为了降低这种依赖性,使用的一种常见的技术就是利用一个不透明指针(opaque pointer)来隐藏一部分实现细节:

class X {

public:

/* ... 公有成员 ... */

protected:

/* ... 保护成员?... */

private:

/* ... 私有成员?... */

class XImpl* pimpl_; // 指向一个被前置声明了的(forward-declared)类

// 之不透明指针

};

[Questions]

[提问]

1.那些部分应该放入Ximpl?有四种常见的原则,它们是:

- 将全部私有数据(但不是函数)放入Ximpl;

- 将全部私有成员(译注:即包括函数)放入Ximpl;

- 将全部私有成员和保护成员放入Ximpl;

- 使Ximpl完全成为原来的X,将X编写为一个完全由简单的前置函数(forwarding functions)(一个句柄/本体的变体)组成的公共接口。

它们各有什么优缺点?你如何从中选择合适的?

2.Ximpl需要一个指向X对象的"反向指针(back pointer)"吗?

[Solution]

[解答]

首先看两个定义:

可见类(visible class):客户代吗所见并操纵的类(在这里即是X)。

pimpl:可见类中隐藏在一个透明指针(也称为pimpl_)下的类实现(在这里即是XImpl)。

在C++中,如果类定义中的任何部分被改变了(即使是私有成员),那么这个类所有的使用者代妈都必须重新编译。为了降低这种依赖性,使用的一种常见的技术就是利用一个不透明指针(opaque pointer)来隐藏一部分实现细节:

这是"句柄/本体"惯用法(handle/body idiom)的一种变体。如Coplien[注1]所记载,这种方法主要用于在共享代码的情况下进行引用计数(reference counting)。

正如Lakos[注2]所指出的那样,"句柄/本体"惯用法(表现为我所称为的"pimpl惯用法"之形式;这样的叫法缘自给其特意取的、易发音的"pimpl_"指针[注3])对于打破编译期的依赖性也是非常有用的。本条款的解答集中讨论这种用法,其中有些讨论总的来讲并不适从于"句柄/本体"惯用法。

使用这个惯用法的主要代价是性能:

1.每一个构造操作都须分配内存。自己定制的分配器(custom allocator)或许可以缓解内存的额外消耗,但这还不是涉及到更多的工作。

2.每一个隐藏成员都需要一个额外的间接层来予以对其访问。(如果被访问的隐藏成员本身又使用到了一个"反向指针(back pointer)"来调用可见类中的函数,那么就会有双重的间接性。)

1.那些部分应该放入Ximpl?有四种常见的原则,它们是:

- 将全部私有数据(但不是函数)放入Ximpl;

这是个不错的开端,因为现在我们得以对任何只用作数据成员的类进行前置声明(forward-declare)(而不是使用#include语句来包含类的真正声明--这会使客户代码对其形成依赖)。当然,我们通常可以做得更好。

- 将全部私有成员(译注:即包括函数)放入Ximpl;

这(几乎)是我平常的用法。不管怎么说,在C++中,"客户代码不应该也并不关心这些部分"就意味着"私有(private)",而私有的东西则最好藏起来(在一些拥有更"自由宽大"之法律的北欧国家里的情况除外)。

对此有两条警告,其中的第一个也就是我在上一段中加上"almost"的原因:

1.即使虚拟函数是私有的,你也不能把虚拟成员函数隐藏在pimpl类中。如果想要虚拟函数覆写基类中的同名虚拟函数,那么该虚拟函数就必须出现在真正的派生类中。如果虚拟函数不是继承而来的,那么为了让之后层级的派生类能够覆写它,其还是必须出现在可见类中。

2.如果pimpl中的函数要使用其它函数,其可能需要一个指向可见对象的"反向指针(back pointer)"--这又增加了一层间接性。这个反向指针通常被约定俗成的称为self_。

- 将全部私有成员和保护成员放入Ximpl;

如此更进一步的做法其实是错误的。保护成员(protected members)绝不应该被放进pimpl,因为这样做等于就是对其弃之不用。无论如何,保护成员(protected members)正是为了让派生类看到并使用而存在的,因此如果派生类无法看到或使用它们的话,它们也就基本上全无用处了。

- 使Ximpl完全成为原来的X,将X编写为一个完全由简单的前置函数(forwarding functions)(一个句柄/本体的变体)组成的公共接口。

这只在少数几个有限的情况下有用,其好处是可以避免使用反向指针,因为所有的服务全部都在pimpl类之中提供了。其主要的缺点是,这样做一般会使得可见类对于继承而言全无用处,无论是作为基类还是派生类。

2.Ximpl需要一个指向X对象的"反向指针(back pointer)"吗?

很不幸,回答通常为"是的"。无论如何,我们会把每一个对象分裂成两部分--只因为我们要隐藏其中一部分。

当可见类中的函数被调用的时候,经常需要使用隐藏部分(译注:即pimpl部分)中的一些函数和数据,以便完成是调用着的请求。这挺好,也很合理。然而可能不太明显的情况是:在pimpl中的函数也经常必须调用可见类中的函数--通常是因为需要调用的函数是公有成员或虚拟函数。

[注1]:James O. Coplien. Advanced C++ Programming Styles and Idioms (Addison-Wesley, 1992).

[注2]:J. Lakos. Large-Scale C++ Software Design (Addison-Wesley, 1996).

[注3]:我以前经常将其写作impl_。与其等价的pimpl_写法其实是有我的朋友和同事Jeff Sumner提出的;Jeff Sumner同我一样对用于指针变量的匈牙利式"p"前缀(译注:即用于命名变量的匈牙利表示法;在该表示法中,指针变量名以"p"开头,意即"pointer")颇为倾心,另外其还对恐怖的双关语有着独到的敏感(译注:pimpl发音与单词"pimple(意即痤疮、丘疹、脓疱、疙瘩、粉刺)"相同)。

(完)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有