template进行编程

本文详细介绍了C++中的模板机制,包括类模板和函数模板,强调了模板在节省代码、提高效率方面的作用。通过示例展示了如何定义和使用模板,以及模板参数的处理规则。还探讨了模板类成员函数的定义和声明,以及模板参数作为设计策略的情况。内容涵盖模板的内联定义、常量表达式参数和模板参数的默认值。
摘要由CSDN通过智能技术生成

前言:Template(模板)能根据用户指定的特定值或特定类型,自动产生一个函数或类。

为什么要有模板呢,举一个例子:

(假定已经想好要定义的BTnode,用以存储结点数值,和左右孩子指针)

这是二叉树的结点定义。

为了存储不同类型的值,我们必须还要实现不同的BT_node类,比如 int_BTnode,double_BTnode

template机制“与类型相关的”和“独立于类型之外”的两部分分离开来。

一些成员函数的操作行为不会随着包含这些成员函数的类不同而不同,普通模板也是。

在一个类模板中,与类型相关的部分会被抽离出来,成为一个或多个参数。

示例如下:

class string_BTnode{
public:
//...
private:
    string _val;
    int _cnt;
    string_BTnode *lchild;
    string_BTnode *rchild;
}
template<typename valType>class BTnode;//类模板前置说明
//...
template<typename valType>
class BTnode{
public:
//...
private:
    valType _val;
    int _cnt;
    BTnode *_lchild;
    BTnode *_rchild;
};

定义该类对象的方式如下:
BTnode<int>bti;
BTnode<string>bts;

在类模板和类成员的定义中,可以用模板参数列表进一步限定类模板。

示例如下:

template<typename elemType>
class BinaryTree{
public:
//...
private:
    BTnode<elemType> *_root;
//BTnode(模板)类必须以模板参数列表加以限定的例子
}

指定某个实际类型作为BinaryTree模板类的参数,如:BinaryTree<string> st ,指针_root指向一个结点值类型为stringBTnode类类对象

如果BinaryTree<int> it; ,指针_root指向值类型为intBTnode类对象。

BTnode模板类和BinaryTree模板类配合使用,所以这两个类要建立friend关系

template<typename Type>
class BinaryTree;//BinaryTree类的前置声明
template<typename valType>
class BTnode{
    friend class BinaryTree<valType>
    //...
}


模板类的定义

给模板类定义一个内联成员函数,如同给非模板类定义一个内联成员函数一样。在模板类的外部定义内联函数的语法示例如下:
template<typename elemType>
inline BinaryTree<elemType>::BinaryTree():_root(0){}
//这个类模板的内联成员函数是带成员初始化列表的构造函数
另外,在类作用域运算符出现后,其后所有东西都被视为类定义范围内。
BinaryTree<elemType>::BinaryTree()

上述例子中,第二次出现的BinaryTree被视为类定义范围内,因为在类作用域运算符出现后,所以不需要加template<typename elemType>来限定,而第一次出现的BinaryTree前需要加template<typename elemType>


Template类型参数的处理

处理模板类型的参数时,无法知晓用户实际要用的类型是否为 语言内置 类型
实际处理模板类型的参数时无论类型是内置类型还是 class (类)类型,都可能被指定为模板类的实际类型。所以有了一个规则如下

规则:将所有的模板类型参数视为class类型处理

于是,模板类的实际类型参数,声明为const类模板类的实际类型名 &参数名。示例如下:

template<typename valType>
inline BTnode<valType>::BTnode(const valType &val):_val(val)
{
//将模板类型valType视为class类型
_cnt=1;
_lchild = _rchild = 0;
}

实现一个 Class Template

关于new表达式

new表达式可分解为两个操作:

1. 向程序的空闲空间请求内存,若分配到足够的空间,则返回指针,指向新对象;若未分配到足够空间,则抛出异常 bad_alloc ( 异常处理 )
2. 如果 new 类型名(初值),则新对象被初始化。

示例如下:

_root = new BTnode<elemType>(elem);

其中elem被传入BTnode模板类的类构造函数。分配内存失败,初始化操作(类构造函数操作)不会发生。

模板类成员函数的定义/声明

示例如下:(具体看格式)

一般模板类成员函数定义:

template<typename valType>
void BTnode<valType>::insert_value(const valType &val)
{
    if(val == _val)
    {
        //...
    }//二叉树有这个结点,就把结点插入次数记录下来即可
    if(val<_val)
    //插入的结点比当前结点小,就插到当前结点的左孩子(如果当前结点的左孩子没有)
    {
        //...
    }
    else
    //插入的结点比当前结点大,插入当前结点的右孩子
    {
        //...
    }
}

内联模板类成员函数定义:

template<typename elemType>
inline void BinaryTree<elemType>::remove(const elemType &elem)
{
    if(_root)
    {
        if(_root->_val==elem)
        {
            remove_root();
        }
        else
        {
            _root->remove_value(elem,_root);
        }
    }
}

一般模板类成员函数的声明:

template<typename valType>
void BTnode<valType>::
remove_value(const valType &val,BTnode *&prev);

模板类成员函数的定义/声明格式:

template<typename 自定义类型名(占位符)>

(按情况加inline)返回类型 模板类类名<自定义类型名>::

模板类成员函数名(参数表(比如const 自定义类型名 &参数名等));或者{//...}

函数参表出现 *&的说明

为避免当模板自定义类型名 被指定为 class 类型 时,因传值(不带 & )而产生的 昂贵赋值开销。
不改变参数值,就在该参数名的最前面加个 const ,即 const 类型名 参数名
* & 即为指针的引用
* & 出现在函数参表中的意思是“既想改变传入形参的实参指针(或者说形参指针)所指的对象,又想改变实参(或说形参)指针本身”

以FunctionTemplate完成的Output运算符

一个以模板函数完成的输出(<<)运算符

非模板函数形式的重载运算符函数的声明:

ostream& operattor<<(ostream&,const BinaryTree<int>&);

其定义与调用如下:

template<typename elemType>
inline ostream&
operator<<(ostream &os,const BinaryTree<elemType>&bt)
{
    os<<"Tree:"<<endl;
    bt.print(os);
    return os;
}
int main()
{
    BinaryTree<string>bts;
    cout<<bts<<endl;
//编译器将elemType指定为string,产生一个对应的(针对BinaryTree<string>类型的),,运算符。
    BinaryTree<int>bti;
    cout<<bti<<endl;
}

C++中可以用常量表达式作为模板参数,而且以常量表达式作为模板参数(<>内的参数)还可以给这个模板参数提供默认值,示例如下:

template<int len,int beg_pos>
class num_sequence{
//...
}
template<int len,int beg_pos>ostream&
//<<运算符的模板函数定义
operator<<(ostream&os,const num_sequence<len,beg_pos>*ns)
{
    return ns.print(os);
}

 Template 参数作为一种设计策略

将某种特定的命名规范强加于被当作参数的类身上:每个类都必须提供某模板类中调用到的函数。这样的独特设计很高级,说明模板类的类型参数不光可用以传递元素类型,还可以传递class类型。示例如下:

 非模板内定义成员模板函数

 模板内定义成员模板函数

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值