栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C++ 3 】模板与自动指针

C/C++/C# 更新时间:发布时间: 百科书网 趣学号

模板与自动指针
  • 一、模板函数(compare)
    • 1.一般模板函数
    • 2.特化模板函数模板
  • 二、模板类(Queue)
    • 1.成员模板函数
    • 2.模板特化
      • 1.模板成员函数特化
      • 2.模板类特化
  • 三、类模板实现智能指针 AutoPtr
    • 1.构造函数
    • 2.析构函数
    • 3.运算符重载

一、模板函数(compare)

引出问题
       函数重载通常用于处理不同的数据类型完成类似的操作,但是有时一个操作可以处理不同的数据类型,这时重载就会出现,参数不同,方法相同的问题。而这时如果能够写一段通用代码处理多种不同数据,便会使代码可重用性大大提高。

       使用函数模板就是为了这一目的。程序员只需对函数模板编写一次,然后基于调用函数时提供的参数类型,编译器会自动产生相应的函数来正确的处理该类型的数据,又称为函数模板的实例化。

注意:函数模板本身在调用前不会生成任何目标代码,只有在调用时才生成具体的目标代码。

参数化设计:
       通用代码不受数据类型的影响,并且可以自动适应数据类型的变化。

模板支持参数化设计

参数化多态性:
       就是将程序所处理的对象的类型参数化,使得一段程序可以用于处理不同类型的对象。

通过模板实现参数化多态性

1.一般模板函数

定义形式:

template<模板参数表>
类型名 函数名(参数表)
{
	函数体的定义
}

所有函数模板的定义都是用关键字template开始。

模板参数表中的类型参数可以用来指定函数模板本身的形参类型、返回值类型,以及声明函数中的局部变量。

模板参数表由用逗号分割的模板参数构成,可以包括以下内容:
       1) class(或template)标识符,指明可以接受一个类型参数,可以是预定义类型或自定义类型;
       2)类型说明符 标识符,指明可以接受一个由 ”类型说明符“所规定类型的常量作为参数;
       3)template<参数表> class 标识符,指明可以接受一个类模板名u走位参数。

举例,代码如下:
       定义一个可以比较多种数据类型的模板函数
       template,定义一个数据类型T,在函数中就可以像int、char一样使用这个数据类型

template
int compare(const T &v1, const T &v2){

    if(v1v2) return 1;
    return 0;
}

       测试,将int型和double型输入函数测试。

void test1(){
    int a1 = 2, a2 = 4;
    cout< 
2.特化模板函数模板 

       模板函数对某特定数据类型需要特殊处理,参数在某种数据特定类型下的具体实现称为模板的特化

       对于模板函数compare(),在比较字符串类型时,如果实参为字符串的字符指针,方法显然不能使用数值型比较方法,否则比较的是指针的大小,所以在这种特殊情况下,要将模板特化。

注意:特化的模板函数声明可以写在头文件中,但是函数体实现只能写在cpp文件中。

举例代码如下:
模板特化函数实现时,参数表为空,函数名后标明特化处理的数据类型,本例

void test1(){
    int a1 = 2, a2 = 4;
    cout<//写在cpp文件
int compare(const char * const &v1, const char * const &v2){
    return strcmp(v1,v2);
}

二、模板类(Queue)

模板类,使得类中的某些数据成员、某些成员函数的参数、返回值或局部变量能取不同类型。
       声明语法形式:

template<模板参数表>
class 类名
{
	类成员声明
}	

注意:
       1、类成员的声明方法与普通类几乎相同,只是还可以用到模板的类型参数
       2、如果需要在模板类以外定义其成员函数,需要采用以下形式:

template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数名)

       3、模板类声明自身不是一个类,只有被引用时,模板才根据引用的需要生成具体类。

       4、用模板类建立对象时,语法如下:

模板名<模板参数表> 对象名;
1.成员模板函数

       前面已经介绍了模板函数,那么定义在类内的模板函数即为成员模板函数,此时参数类型即包括类的参数类型,又包括模板自身的参数类型。

类模板内声明
声明与正常成员函数相比多了template

	template
    Queue(It beg, It end):head(0),tail(0){
        copy_items(beg,end);
    }

    template
    void assign(It beg, It end);

类模板外实现
实现时既有类的template 又有模板函数的template

template//类模板参数表
template
void Queue::assign(It 	beg, It end)
{
    destroy();
    copy_items(beg,end);
}

template//类模板参数表
template
void Queue::copy_items(It beg,It end )
{
    while(beg!=end){
        push(*beg);
        ++beg;
    }
}
2.模板特化 1.模板成员函数特化

       前面已经提到,类模板的类型参数可以给它的成员使用,当成员函数使用了类型参数,可能会遇到前面说到的某种数据类型要特殊处理的问题,那么就会存在模板成员函数特化的情况

如下当向队列中添加或删除元素时,如果实参是字符串对应的指针,那么需要特殊处理

template
void Queue::pop(){
    QueueItem * p = head;
    head = head->next;
    delete p;
}

template
void Queue::push(const Type& val){
    QueueItem * pt = new QueueItem(val);
    if(empty()){
        head = tail = pt;
    }else{
        tail->next = pt;
        tail = pt;
    }
}

template<>
void Queue::push(const char * const &);
template<>
void Queue::pop();
2.模板类特化

       如同模板函数特化一样,模板类对某种数据类型进行特殊处理时,将模板类进行特化。
将上面的模板类可以如下特化:

template<>
class Queue{
public:
    void Push(const char* str){real_queue.push(str);}
     void Pop(){real_queue.pop();}
     bool isEmpty()  {return real_queue.empty();}
     string front() const {return real_queue.front();}
     friend ostream & operator<<(ostream& os, Queue &que){
         os< real_queue;

 };

那么特化时就会面临,两种情况
       1)将所有模板成员函数特化
       2)将部分模板成员函数特化

三、类模板实现智能指针 AutoPtr

对内存的思考

C++ 程序中的内存分为两个部分:
       1)栈:在函数内部声明的所有变量都将占用栈内存。
       2)堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。

       栈中的变量使用结束,系统会自行释放它们的内存,而堆中的变量使用完后,系统不会自动释放他们的内存,不用delete进行销毁,会一直占用堆的内存。

       数据或指针不用new创建,会占用栈的内存,那么也不需要delete
       而new是动态申请堆的内存,用new创建变量,就需要delete。
       int *p= new int(10), p的内存在栈,int的内存在堆。

那么能否设计一个智能指针,解决在动态申请的内存用完后,能够自动释放内存呢。

指针的要求:
       存放一个变量的地址,通过指针可以访问这个变量的值
又要求当使用结束后能够自动释放内存。

那么可以设计一个类,满足以下要求:
1)可以访问变量;
       可以通过设计一个类成员,而类成员的数据类型又是不确定的,可以将类设计成类模板,类成员类型为参数类型。
2)能够自动释放内存;
       需要设计一个标志,来判断是否存放的变量的值是否仍在使用,无则释放内存
3)同时还要满足指针的=, *及->运算。

template
class AutoPtr
{
public:
		构造函数
		析构函数
		运算符重载

private:
    void declUser();
    Type * m_nData;
    int * m_nUser;
};

需要添加一个decrUser()函数来控制m_nUser,并当m_nUser为零时释放m_nData和m_nUser的内存

template
void autoPtr::declUser(){
    --(*m_nUser);
    if(*m_nUser == 0){
        delete m_nData;
        m_nData = 0;
        delete m_nUser;
        m_nUser = 0;
     }
}


1.构造函数
template
autoPtr::autoPtr(Type* data){
    m_nData = data;
    m_nUser = new int(1);  //int i =1;m_nUser = i;,函数结束 i释放内存,
}

template
autoPtr::autoPtr(const autoPtr& h){
    m_nData = h.m_nData;
    m_nUser = h.m_nUser;
    (*m_nUser)++;
}

2.析构函数
template
autoPtr::~autoPtr(){
//    if(*m_nUser == 0)
//        cout<<"autoPtr destoried"< 

v

3.运算符重载
    Type* operator->(){
        return m_nData;
    }
    
    Type& operator*(){
        return *m_nData;
    }
    
    const Type* operator->() const{
        return m_nData;
    }
    
    const Type& operator*() const{
        return *m_nData;
    }
    
 
template
autoPtr& autoPtr::operator=(const autoPtr& h){
    
    declUser();
    m_nData = h.m_nData;
    m_nUser = h.m_nUser;
    (*m_nUser)++;

}
void testautoptr(){

    autoPtr pt1(new int(10));
    cout<<*pt1<
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/587394.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号