微信号:gh_5f9337df4e69

介绍:讨论和学习C/C++的编程知识

第九十四讲 模板模板参数

2014-10-19 21:13 零灵柒

当我们学习了标准库后,我们再回头去看看以前我们实现的那个游戏模板(第五十二讲 类模板(1)),我们可能就会有更好的实现方案,比如我们想要重新分配空间,重新改变电子表格大小会更容易得多,当然重要的更加安全得多,也许你可能和我一开始学习版本的时候这样想,我们可以这么做:
//=============================

template<typename T,typename C>
class Game{
public:
Game(size_t width,size_t height):m_width(width),m_height(height){
m_c = new C[m_width];
for(size_t i=0;i<m_width;++i)
m_c[i].resize(m_height);
}
}

//.......
//........
private:
void copyFrom(const Game<T,C>&);
C* m_c;
size_t m_width,m_height;
};
==================================

这可能是每个学习模板的初学者都惯用的方法,当然我也不例外,因为如果我们一开始就打算使用标准库的容器来作为了这个模板的实现的话,那么我们一开始就基本确定了方法,就像上面一样,在为每个列分配空间的时候我们可以使用resize来给容器的成员方法来实现,当然,当我们想要实例化这个模板的时候,我们选择的容器必须得支持resize这个方法(关于更多的实现,这里就不多举,可以回头去看看第五十二和五十三两讲的内容),有了这个模板,我们可以这样来实例化他:

//==========================

Game<int,vector<int> > intGame;
Game<double,deque<double> > doubelGame;

我们像上面用他完全没问题,但是我们却不能这样用:
Game<int,int> intGame;
//ok,这里将不能通过编译,因为int没有相应的resize成员方法

//=============================
这样一来大家或许会觉得问题变得有些麻烦了,我指的麻烦当然是指使用上变得麻烦,那么我们为什么还要这样费劲呢?因为没有白吃的午餐,我们选择了简单优雅的实现,那就必须得付出一点点的麻烦,不过C++的魅力当然不只这么简单,如果我们一开始就只需要一个vector的,那么我们就可以将容器指定为他就好了:
//=============================
template<typename T,typename C=vector<T>>
class Game{
//................
}
===============================
现在我们可以像一样方便的使用了:
//============================
Game<int> intGame;
Game<double> doubleGame;

Game<int ,list<int> >
//像上面这般都没问题,那么如果我们写出下面的代码会怎样呢:
Game<int,list<std::string> > stringGame;
//哦,好像有些风马牛不相及了,但是我们谁又能保证我们不会写出这么范二的代码来呢,想要杜绝这么二的事情发生,唯一的办法就是.........我们今天要说的模板的模板参数
//===========================

关于模板的模板参数我们上面已经见识过了,vector是一个模板,我们将这个模板当作Game模板的参数,但我们这种使用也太不明智了,我们需要的是...............
Game<int,vector> intGame;
Game<int,list> intlistGame;
..........
我们无需明显的指定参数的实例化就能够使用,这样一来我们就不用担心写出范二的代码了

好吧,就进入主题吧,首先我们来看看vector的定义,如果有疑问可以回头去看看(第六十五讲 细说vector):
//=============================
template<typename T,typename allocator = allocator<T> >
class vector;
//==============================

这就是我给大家说过的vector,标准库就是这么定义来着的,所以当我们想要使用模板作为参数时,我们应该做得更加全面一些,我之所以先给大家说了vector的定义,是因为我担心接下来写出来的东西可能会令大家一时无法接受,比如:
//==============================
template<typename T,template<typename U,
typename allocator = allocator<U> > class C=vector>
class Game{
//实现方法完全一样
};
//==============================
现在我们可以写出很方便的代码,而且保证你再不会范二,只要能够满足第二个模板第一的容器都可以拿来实例化Game模板,对于模板,还有两个比较高级的用法,那就是指针和引用参数的用法,今天就一道说了吧。
//==============================
template<const char* name>
class Game{
//内容略.....
};
================================
我们实例化这个模板的时候可能会遇到一些麻烦,这里我们看到了,这个模板需要一个char指针去实例化,通常情况下我们遇到这类型的参数的时候可以直接使用"XXX"给他,这没问题,但是现在在模板里面后,这样做就会有问题,因为这里需要的是一个具有外部链接属性的全局对象,所以我们想要实例化这个模板,我们只能...........
//=======================
extern const char name[] = "Test";
int main(){
Game<name> charGame;
//...................
}

//========================
对于引用也是一样的,必须具有外部连接属性的全局对象:
//===========================
template<typaname T,const T&>
class Game{.........}
==============================
我们这样做只是简单的想要给每一个元素一个初值,这么做很多时候是很有必要的,如果你们真正的体验过的话,因为内部类型往往都会没有默认构造函数的,所以我们使用了内部类型,我们得到是一堆毫无意义的随机值,这常常不是我们想要的结果,所以我们有时候会踏上使用引用参数的模板的道路,他的实例化和指针一样:
//============================
extern const int zero = 0;
int main(){

Game<int,zero> intGame;
//.........
}
===============================
ok,对于C++的内容我想不起还有什么技术和大家讨论的了,开课这么久,从半懂半懵的C语言说到C++,我确实没研究过C,一开始就从C++着手的,厚着脸皮顶着压力说前三十讲的C内容,当然前三十讲的内容只是想让大家知道C++的基础,在后面的内容中大家也看到说的东西远超C++的基础,这是我的过错,原本当初开这个公众微信号的时候只是想和大家谈谈基础的,没想到后面越说越深,基础说得很少,再说了少许的基础后就带着大家进入class,然后是标准库,各种实现技术,有时候我在想,我是不是我说我的,你们看你们的,终究还会是说不到一块去呢?当然如果真有这种情况发生,这还得怪我自己,多半是因为我没把问题给大家阐释清楚,好吧,今天总算是告一段落,以后不会再和大家讨论这些实际应用中可以无法用到的技术,我们接下来有空的话就来讨论一些boost组件的用法,那样会显得很轻松很愉快的。

==============================
回复D或者d查看目录,回复数字查看相应的章节

 
C/C++的编程教室 更多文章 写在开篇 第一讲 Hello World 第二讲 printf()(1) 第三讲 printf()(2) 第四讲 scanf()
猜您喜欢 ✪​报名|7月6日『大数据商业应用与创新峰会』 闪耀北京 说出来都是泪!设计师听了会崩溃的那些话 书接上文:薛定谔的猫是如何诞生的? 元数据管理的未来趋势——企业级元数据管理(EMM) 新消费升级时代已经来临,怎么消费最在行?