第十六章 模板介绍
模板中的常量
/**
* 书本:【ThinkingInC++】
* 功能:模板中的常量
* 时间:2014年10月7日18:45:01
* 作者:cutter_point
*/
#include<cstdio>
#include<iostream>
#include"../require.h"
usingnamespace std;
template<classT, int size=100> //这个size不写到类中,但是使用的时候就如同是成员函数中的
class Array
{
T array[size];
public:
T& operator[] (int index) //重载下标操作符
{
//验证数据越界
require(index >= 0 &&index<size, "Index out of range");
return array[index];
}
int length() const { return size; }
};
classNumber
{
float f; //等会作为数据类型,当成模板的参数
public:
Number(float ff=0.0f) : f(ff) {}
Number& operator=(const Number&n) //赋值运算操作符
{
f=n.f;
return *this; //最后返回当前的对象,这是一个值拷贝,吧外面的Number对象拷贝到这个对象
}
operator float() const { return f; } //float(),返回当前值
friend ostream&operator<<(ostream& os, const Number& x) { return os<<x.f;} //输出,友元
};
template<classT, int size=20>
classHolder
{
Array<T, size>* np;
public:
Holder() : np(0) {}
T& operator[] (int i)
{
require(0 <= i &&i<size); //判定是不是在范围内
if(!np) np=new Array<T,size>; //判定是不是为空,如果为空的话,就创建一个,不为空直接返回值
return np->operator[](i); //返回创建的对象的值
}
int length() const { return size; }
~Holder() { delete np; }
};
intmain(int argc, char *argv[])
{
Holder<Number> h;
for (int i=0 ; i<20 ; ++i)
{
h[i]=i;
}
for (int j=0 ; j<20 ; ++j)
{
cout<<h[j]<<endl;
}
return 0;
}
类Holder很像Array,只是它有一个指向Array的指针,而是推迟到第一次访问的时候,这个叫懒惰初始化。
作为模板的Stash和Stack
头文件TStack.h
/**
* 书本:【ThinkingInC++】
* 功能:这是用模板写一个栈类的头文件
* 1》使用嵌套类
* 2》添加构造函数,析构函数,添加,删除,弹出
* 时间:2014年10月7日18:45:24
* 作者:cutter_point
*/
#ifndefTSTACK_H_INCLUDED
#defineTSTACK_H_INCLUDED
template<classT>
class Stack
{
struct Link
{
T* data; //指向数据成员
Link* next; //指向下一个节点
Link(T* dat, Link* nxt) : data(dat),next(nxt) {}
}*head;
public:
Stack() : head(0) {} //构造函数
~Stack()
{
while(head)
delete pop(); //调用pop来回收空间,只要还有剩余的节点那么就回收
}
void push(T* dat) //添加数据
{
head=new Link(dat, head); //吧头节点向下压,吧新的节点作为头结点
}
T* peek() const { return head ?head->data : 0; } //返回元素但是不删除元素
T* pop() //返回并且删除元素
{
if(head == 0) return 0; //如果头结点为空,那么直接返回
//如果不为空
//吧头结点的数据保存,有一个指针指向头节点
T* result=head->data;
Link* oldHead=head;
//断开头结点
head=head->next;
//回收原来的头节点
delete oldHead;
//返回原来节点的数据
return result;
}
};
#endif //TSTACK_H_INCLUDED
运行文件TStackTest.cpp:
/**
* 书本:【ThinkingInC++】
* 功能:用模板栈实现对本文件的文件流读取
* 时间:2014年10月7日18:45:59
* 作者:cutter_point
*/
#include"TStack.h"
#include"../require.h"
#include<fstream>
#include<iostream>
#include<string>
usingnamespace std;
class X
{//为了跟踪信息,反映Stack容器清除对象
public:
//这里定义为虚函数是为了以后如果有派生类的话,对象可以存放相应的派生类
virtual ~X() {cout<<"~X"<<endl; }
};
int main()
{
ifstream in("TStackTest.cpp");
assure(in, "TStackTest.cpp");
Stack<string> textlines; //存放所有的数据
string line; //存放一行
while(getline(in, line))
textlines.push(new string(line)); //存放进去,这里的参数是一个引用,所以必须创建一个新的string给它
//显示出来
string* s;
for(int i=0 ; i<46 ; ++i)
{
//如果全部弹出了,那么直接跳出循环
if((s=(string*)textlines.pop()) ==0)break;
cout<<*s<<endl;
}
delete s; //回收上面创建的s;
Stack<X> xx;
for(int j=0 ; j<10 ; ++j)
xx.push(new X);
return 0;
}
头文件AutoCounter.h,报告自身的创建和销毁
/**
* 书本:【ThinkingInC++】
* 功能:报告自身的创建和销毁
* 时间:2014年10月7日18:46:37
* 作者:cutter_point
*/
#ifndefAUTOCOUNTER_H_INCLUDED
#defineAUTOCOUNTER_H_INCLUDED
#include"../require.h"
#include<iostream>
#include<set>
#include<string>
classAutoCounter
{
static int count; //计数
int id;
class CleanupCheck //嵌套类
{
std::set<AutoCounter*> trace;
public:
void add(AutoCounter* ap) {trace.insert(ap); }
//size_type erase( const key_type&key );删除等于key值的所有元素
//(返回被删除的元素的个数)。
void remove(AutoCounter* ap) {require(trace.erase(ap) == 1, "这个数值删除超过1次"); }
~CleanupCheck()
{
std::cout<<"~CleanupCheck()"<<std::endl;
require(trace.size() == 0, "这个AutoCounter没有清除干净");
}
};
static CleanupCheck verifier; //这个其实就是一个set,外加一些操作
//吧构造函数私有,拷贝赋值函数私有,拷贝赋值运算符私有,避免外部创建对象
AutoCounter() : id(count++)
{
verifier.add(this); //吧当前对象加入到set中
std::cout<<"created["<<id<<"]"<<std::endl;
}
AutoCounter(const AutoCounter&);
void operator=(const AutoCounter&);
public:
static AutoCounter* create() { return newAutoCounter(); }
~AutoCounter() {std::cout<<"destroying["<<id<<"]"<<std::endl;verifier.remove(this); }
friend std::ostream&operator<<(std::ostream& os, const AutoCounter& ac) //引用
{
return os<<"AutoCounter"<<ac.id;
}
friend std::ostream&operator<<(std::ostream& os, const AutoCounter* ac) //引用
{
return os<<"AutoCounter"<<ac->id;
}
};
#endif //AUTOCOUNTER_H_INCLUDED
感想:
1、对于代码的目的是为了简化问题而不是让问题复杂化。
所以以后有什么不会的可以从这个方面去探讨。