读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template
标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况。
假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对之求逆运算。因为方阵的元素可以有多种类型,同时方阵的维数(方阵大小)也可以不同,像下面这样,我们使用了模板:
template <class T, size_t n>
class SquareMatrix
{
public:
void Invert();
}; int main()
{
SquareMatrix<int, > a;
SquareMatrix<int, > b;
}
模板既可以指定类型,也可以指定其他参量,比如这里的size_t,用来表示方阵的维数。程序看起来是没有问题的,编译也是通过的,但从代码优化上看,还是有空间可以做的。a和b虽然都是元素为int型的方阵,但因为方阵维数不同,因而生成了两个Invert函数,这两个Invert函数的代码只是在循环个数上不同(取觉于方阵维数n),但算法思想完全是一样的。
为了防止编译器生成冗余的代码,我们可以将Invert抽离这里,变成一个以n为参数的函数,像下面这样:
class SquareMatrixBase
{
public:
SquareMatrixBase(T* p) : DataPointer(p){}
void Invert(size_t n){}
private:
T* DataPointer;
}; template <class T, size_t n>
class SquareMatrix: private SquareMatrixBase<T>
{
public:
SquareMatrix() : SquareMatrixBase(Data)
{}
void Invert()
{
SquareMatrixBase::Invert(n);
}
private:
T Data[n * n];
};
这里我们定义了一个BaseSquareMatrix类,这个类可以视为一个工具类,因为SquareMatrix是private继承于它的,我们把算法一致、只与维数n相关的算法函数都放在BaseSquareMatrix中,且将n作为它的Invert()函数的形参,为了使BaseSquareMatrix可以访问数据,从而求逆运算,我们声明了它的成员指针,这个指针将会在构造时指向子类的数据存储空间。
子类SquareMatrix没有大变化,只是在Invert的时候,用了一句代码就搞定了——调用父类的Invert函数,并把维数n传过去。
这样在main函数中,针对类型都是int,但矩阵维数不同的情况,Invert中生成的冗余代码非常少(只有一句话),父类也因为模板参数与维数无法,所以也只生成一份。从这个角度来看,将与参数无关的代码抽离template起到了减少代码冗余度的优化作用。
目前只是说将与类型无关的代码进行抽离(造一个父类,把算法相同的部分提取出来,放到父类),对于不同类型,其实也可以通过void*来实。比如STL,要想令我们使用list<int*>,list<const int*>生成的代码冗余度保持很低,这就需要在相应的函数里面,将之链到父类的一个公共实现版本里面,这个版本的形参是void*。
最后总结一下:
1. Template生成多个classes与多个函数,所以任何template代码都不该与某个造成膨胀的template参数产生相依关系。
2. 因非类型模板参数而造成的代码膨胀,往往可以消除,做法是以函数参数或者class成员变量替换template参数。
3. 因类型而造成的代码膨胀,也可以降低,做法是让带有完全相同二进制表述的具现类型共享实现码。
读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template的更多相关文章
- 读书笔记_Effective_C++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句话是:普通函数既继承接口,也强制继承 ...
- 读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数
class A { private: int a; public: A(int x) :a(x){} A operator*(const A& x) { return A(a*x.a); } ...
- 读书笔记_Effective_C++_条款二十九:为“异常安全”而努力是值得的
还是举书上的例子: void PrettyMenu::changeBackground(std::istream& imgSrc) { lock(&mutex); delete bgI ...
- 读书笔记_Effective_C++_条款三十:了解inline的里里外外
学过基本程序课的同学都知道,inline是内联的关键字,它可以建议编译器将函数的每一个调用都用函数本体替换.这是一种以空间换时间的做法.把每一次调用都用本体替换,无疑会使代码膨胀,但可以节省函数调用的 ...
- 读书笔记_Effective_C++_条款三十九:明智而审慎地使用private继承
private继承的意义在于“be implemented in turns of”,这个与上一条款中说的复合模型的第二层含义是相同的,这也意味着通常我们可以在这两种设计方法之间转换,但书上还是更提倡 ...
- 读书笔记_Effective_C++_条款三十六:绝不重新定义继承而来的non-virtual函数
这个条款的内容很简单,见下面的示例: class BaseClass { public: void NonVirtualFunction() { cout << "BaseCla ...
- 读书笔记_Effective_C++_条款三十二:确定你的public继承继承塑模出is-a关系
这一条款是说的是公有继承的逻辑,如果使用继承,而且继承是公有继承的话,一定要确保子类是一种父类(is-a关系).这种逻辑可能与生活中的常理不相符,比如企鹅是生蛋的,所有企鹅是鸟类的一种,直观来看,我们 ...
- 读书笔记_Effective_C++_条款二十八:避免返回handlers指向对象内部成分
举个例子: class Student { private: int ID; string name; public: string& GetName() { return name; } } ...
- 读书笔记_Effective_C++_条款二十六:尽可能延后变量定义式的出现时间
这个条款从字面意思还是很好理解的,就是在使用这个变量前才去定义,而不是很早就定义了它,而在很后面的时候才去使用.这个条款只适用于对变量声明位置没有要求的语言,比如C++.对于像C或者一些脚本语言,语法 ...
- 读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数
在之前的理论上调用对象的operator=是这样做的 void swap(A& x) { std::swap(a, x.a); } A& operator=(const A& ...
随机推荐
- [jQuery学习系列一]1-选择器与DOM对象
前言: 好久没有更新博客了, 最近想复习下 之前学过的JS的相关内容, 也算是自己的一种总结. 知识长时间不用就会忘记, 多学多记多用!! 下面的程序都可以在下面的网站进行在线调试: http://w ...
- atitit.RESTful服务的概览and框架选型
atitit.RESTful服务的概览and框架选型 1. REST基础概念: 1 2. URL说明: 1 3. 1 4. RESTful框架选型 2 1. spring mvc( recomm) ...
- Leetcode 303 Range Sum Query - Immutable
题意:查询一个数组在(i,j]范围内的元素的和. 思路非常简单,做个预处理,打个表就好 拓展:可以使用树状数组来完成该统计,算法复杂度为(logn),该数据结构强力的地方是实现简单,而且能完成实时更新 ...
- Liferay7 BPM门户开发之29: 核心kernel.util包下面的通用帮助类ParamUtil、GetterUtil使用
与其闭门造车,不如直接开动原装.进口.免费的法拉利. -- 作者说 不多说废话,直接上代码. ParamUtil ParamUtil.GetterUtil是Liferay最重要的帮助类 ParamUt ...
- Android布局优化
前言 本篇文章为Android优化的布局部分,该部分应该是Android中很重要的,无论是在自定义控件中,还是在简单的书写布局时,都应该尽量遵循一些优化原则,这样布局的绘制效率才会更高,体验才能更好. ...
- Android CountDownTimer倒计时器的使用
http://blog.csdn.net/freesonhp/article/details/25904047 在平时我们编程的时候,经常会用到倒计时这个功能,很多人不知道Android已经帮封装好了 ...
- ASP.NET Web API的安全管道
本篇体验ASP.NET Web API的安全管道.这里的安全管道是指在请求和响应过程中所经历的各个组件或进程,比如有IIS,HttpModule,OWIN,WebAPI,等等.在这个管道中大致分两个阶 ...
- Android的Activity屏幕切换动画(一)-左右滑动切换
(国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) Android的Activity屏幕切换动画(一)-左右滑动切换 在Android开发过程 ...
- eclipse android logcat 只显示自己应用程序信息的设置方法
1 elcipse 中往往会在logcat中显示 all message ,而这里面的信息太多,根本没有办法进行区分.如图: 2 我们想显示自己项目的 logcat .下面开始设置. 3 首先点击上面 ...
- 【转】关于TCP和UDP协议消息保护边界的介绍
在 socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发往接收端的包, ...