IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++实验三 模版学习记录 -> 正文阅读

[C++知识库]c++实验三 模版学习记录

一.模版函数

? ? ?1.一般模版函数

?如上图,定义了一个交换变量值并打印在控制台的函数模版,通过template预先声明这是一个模版,并在<>内告诉编译器T1,T2是个一般化的变量

? ? ?2.特化模版函数

与上图代码的区别在于template<>内不声明如T1,T2这样的一般化变量,这也就意味着特化模版函数内的参数必须全部指定

学到这里的时候我感觉十分困惑,因为这样一来特化模版函数与普通函数似乎不存在区别

百度的结果也告诉我大部分时候它们的作用是差不多的,只是同名的特化模版函数与普通函数可以同时存在而不会发生重定义,并且编辑器会优先调用普通函数(因为只有确定需要使用模版函数时它才会被生成),这种现象有点类似于重载

https://bbs.csdn.net/topics/330199640

二.模版类?

? ? ?1.类模版

模板类实际上是建立一个通用的类模板后实例化出的类。其数据成员、成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表,只有使用类模版定义对象后,编辑器才会将实际的类型取代其虚拟的类型

#include <iostream>
#include <string>
using namespace std;

template <class T1,class T2>
class Li
{
public:
    T1 a;
    T1 b;
    T2 a_name;
    T2 b_name;
    Li(T1 a,T1 b,T2 a_name,T2 b_name){
    	this->a=a;
    	this->b=b;
    	this->a_name=a_name;
    	this->b_name=b_name;
	}
    bool maxT();
};

template<class T1,class T2>
bool Li<T1,T2>::maxT()
{ 
    if(a>b){
    	cout<<a_name<<">"<<b_name<<endl;
    	return a;
	}
    if(a<b){
    	cout<<a_name<<"<"<<b_name<<endl;
	    return b;
    }
    else{
    	cout<<a_name<<"="<<b_name<<endl;
    	return a;
	}
}
int main()
{
    Li<int,string> test(18,19,"Aa","Bb"); 
    test.maxT();
    return 0;
}

可以看出,在template声明T后,整个类内都可以使用,如果在类的外部书写其的函数,则前面也要加上相同的template声明,且类名后要加<T>与声明一致,否则经实测编译器会报错(哪怕实际上该类外函数不需要用到这么多不同变量)

类模版stack举例:

#include<iostream.h>
const int size=10;
template<class T>                     //模板声明,其中T为类型参数 
class Stack{                          //类模板为Stack 
 public:
  void init()
  {
   tos=0;
  }
  void push(T ob);                    //声明成员函数push的原型,函数参数类型为T类型
  T pop();                            //声明成员函数pop的原型,其返回值类型为T类型
 private:
  T stack[size];                      //数组类型为T,即是自可取任意类型 
  int tos; 
};
template<class T>                     //模板声明 
void Stack<T>::push(T ob)             //在类模板体外定义成员函数push 
{
  if(tos==size)
   {
    cout<<"Stack is full"<<endl;
    return;
   }
  stack[tos]=ob;
  tos++; 
}
template<typename T>                  //模板声明 
T Stack<T>::pop()                               //在类模板体外定义成员函数push
{
  if(tos==0)
   {
    cout<<"Stack is empty"<<endl;
    return 0;
   }
  tos--; 
  return stack[tos];  
}
int main()
{
 //定义字符堆栈 
 Stack<char> s1;                        //用类模板定义对象s,此时T被char取代
 s1.init();
 s1.push('a');
 s1.push('b');
 s1.push('c'); 
 for(int i=0;i<3;i++){cout<<"pop s1:"<<s1.pop()<<endl;}
 
 //定义整型堆栈 
 Stack<int> s2;                        //用类模板定义对象s,此时T被int取代
 s2.init();
 s2.push(1);
 s2.push(3);
 s2.push(5); 
 for(int i=0;i<3;i++){cout<<"pop s2:"<<s2.pop()<<endl;} 
 
 return 0; 
}

? ? ?2.成员模版函数

class Printer {
public:
    template<typename T>
    void p(T pri) {
        cout << pri <<endl;
    }
};

int main()
{
    //Li<int,string,int> test(18,19,"Aa","Bb"); 
    //int m=test.maxT();
    //cout<<m<<endl;
    Printer p;
    p.p(1); 
    return 0;
}

? ? ?3.模版特化

(1)模版成员函数特化

class Printer {
public:
    template<typename T>
    void p(T pri) {
        cout <<"T:"<<pri <<endl;
    }
   
};

template<>
    void Printer::p<int>(int pri){
    	cout <<"int:"<<pri <<endl;
	}

int main()
{
    //Li<int,string,int> test(18,19,"Aa","Bb"); 
    //int m=test.maxT();
    //cout<<m<<endl;
    Printer p;
    p.p<int>(1); 
    return 0;
}

实测中共三点需要注意:

one

在类内定义了成员函数模版后,必须在类外声明特化函数的template<>,否则会报错

two

定义了成员函数模版和特化后,使用该函数时后面必须要写<>并给其指定参数类型,而不能省略

如果该参数类型下有特化函数,则优先使用特化函数,否则调用模版函数(如上面代码,指定int时优先调用特化函数,指定double时因为没有特化函数所以用模版函数)

three

特化函数中<>内指定的参数类型在特化函数中的使用必须与模版函数对应的T在模版函数中的使用相对应

如上面T特化为int后,在该特化函数中原本输入的T必须变为int,不能这样写:

void Printer::p<int>(string?pri){

(2)模版类特化

template<typename T>
class Printer {
public:
    //template<typename T>
    void p(T pri) {
        cout <<"T:"<<pri <<endl;
    }
   
};


template<>
class Printer<int> {
public:
    //template<typename T>
    void p(int pri) {
        cout <<"T:"<<pri <<endl;
    }
   
};


int main()
{
    //Li<int,string,int> test(18,19,"Aa","Bb"); 
    //int m=test.maxT();
    //cout<<m<<endl;
    Printer<int> p;
    p.p(1); 
    return 0;
}

三.模版类(autoPtr)

构造函数

autoPtr(T n)
	{
		ptr = new T;//去掉T*,直接用Private里T*好的ptr
		*ptr = n;
		cout << "new pointer created." << endl;
		cout << *ptr << endl; //这个地方可以输出ptr指向的值
	}

析构函数

	~autoPtr()

拷贝构造函数

SmartPointer(const SmartPointer<T>& obj)	//重新实现拷贝构造函数
    {
    	m_pointer = obj.m_pointer;
    	const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
    }

运算符重载

  T* operator ->()	//重载->操作符
    {
    	return m_pointer;
    }
 
    T& operator *()		//重载*操作符
    {
    	return *(m_pointer);
    }

主函数

int main()
{
    {
    	SmartPointer<int> p1 = new int(12);    //指向一个int堆变量
        cout << "(*p1) = " << (*p1) << endl;
 
	SmartPointer<int> p2 = p1;
	cout << "p1.isNull() = " << p1.isNull() << endl;
	cout << "*p2.get() = " << *p2.get() << endl;
 
	SmartPointer<Test> pt = new Test;    //指向一个Test堆对象
    }
    return 0;
}

智能指针的实现原理就是资源分配,它定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。智能指针的实现机制就是利用类的构造和析构函数(释放资源)是由编译器自动调用的。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-17 12:34:54  更:2021-11-17 12:35:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:49:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码