14.6.5 确保类型的大小相同(2)
在本例中,process_array()按值传递的形参array_proxy是声明为non-const的,这是因为该函数可能想要改动数组中的元素。如果你的函数只要求能够读取的话,将array_proxy<T>按const &传递可能会略微提高一点效率,不过这点效率差别与process_array()自身相对较高的开销相比,可能在任何性能评测中都不会体现出来。
我们可以将这个例子进一步扩展,加入一个Derived_SameSize类型,该类型派生自Base,但没有增加任何额外的内存需求(见12.4节)。现在将Derived_SameSize数组传递给process_array()是合法的,而这得力于新的array_proxy设施的另外两个模板构造函数。
- Derived_SameSize
- : public Base
- {};
-
- void main()
- {
- Base ab[10];
- Derived ad[10];
- Derived_SameSize ads[10];
- process_array(make_array_proxy(ab)); // Ok
- process_array(make_array_proxy(ad)); // 编译错误!好!
- process_array(make_array_proxy(ads)); // 好!非常聪明!
- }
这就为我们讨论的问题提供了一种彻底的解决方案。该解决方案是高效的(在任何一个说得过去的编译器上它都没有任何额外开销),是类型安全的,并且完全使得函数的设计者能够防止潜在的误用,或者更确切一点说,让代码能够更强地抵御派生类数组的误用。此外,它还足够智能,允许派生类跟父类具有相同大小的情况通过,并且允许它们的数组被"代理"!
最后一个优点是现在再也不可能将错误的数组长度传给process_array了,而在原先的两个参数(其中一个代表数组长度)的版本中这种危险是时时存在的。这个优势使我们得以遵从DRY原则。
由于该技术并不能对类继承体系提供保护,所以人们可能会争辩说它不能有效阻止传递具有继承关系的类实例。但是我认为不应该这样来看待这个问题。是那些函数--包括自由函数、模板算法、成员函数等--它们自己需要被保护不让外界代码传进错误的类型。由于为这些函数指定array_proxy<T>而非T*类型的形参是代码作者的职责范围,所以他们必须自己考虑这些保护。