zoukankan      html  css  js  c++  java
  • 函数模板与类模板

    模板

    学习模板,使用模板让我们的代码能最大限度上的重用

    一、模板的概念

    1、模板与泛型编程

    1.泛型编程:指的就是编写与类型无关的逻辑代码,在泛型编程中,编写的代码可以作用多种类型的对象

    2.模板:就是实现代码重用的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了代码的重用性。模板就是泛型编程的基础

    2、模板分类

    1.函数模板

    2类模板

    二、函数模板

    1、函数模板是什么

    1.函数模板不是一个实体函数,编译器不会对一个函数模板生成可执行代码。定义函数模板之后只是说对一个函数功能框架的一个描述,只有在调用的时候才会为其生成可执行代码

    2、函数模板的定义

    1.定义:
    template<typename T>
    返回值类型  函数名(参数列表)
    {
        函数体;
    }
    template:模板的关键字
    <>:类型的参数列表
    typename:用来声明类型参数,也可以用class
    T:形参类型的名字
    //注意:类型的参数列表中是可以有多个类型的,比如tempplate<typrname T1,typename T2>,写法和函数的形参列表写法一样
    

    3、函数模板示例

    template<typename T>
    void fun(T &a,T &b)
    {
        cout<<a<<endl<<b<<endl;
    }
    //定义:
    int a=1,b=2;
    char c='x';
    
    

    4、函数模板和普通函数

    1.函数模板和普通函数一样都是可以重载的,函数模板与普通函数也能构成重载

    template<typename T>
    void fun(T a, T b)
    {
    	cout << "我是函数模板" << endl;
    }
    void fun(int a, int b)
    {
    	cout << "我是普通函数" << endl;
    }
    template<typename T1, typename T2>
    void fun(T1 a, T2 b)
    {
    	cout << "我是第二个函数模板" << endl;
    }
    //fun(1,'A');
    //这样是调用的第三个fun函数,因为他会优先调用更好匹配的函数模板
    

    2.如果出现了函数模板与普通函数之间的重载,优先调用普通函数

    3.如果函数模板可以产生一个更好的匹配,那么选择模板

    4.想要强制使用模板,那么就可以使用显示指定类型调用

    5.函数模板实际上就是多了一个类型的参数列表,让我们在使用这个函数模板的时候可以传类型,定义了一个函数的框架,而不用确定类型,可以使用这个函数模板的时候再来确定类型

    #include<iostream>
    using namespace std;
    //模板头,定义了类型的参数列表,可以传一个类型进来
    //这个类型T可以在这个模板头下面的函数中进行使用
    template<typename T>
    T fun(T a, T b)
    {
    	return a + b;
    }
    /*
    在调用的时候,编译器会把函数模板转为模板函数(确定T的类型)
    int fun(int a,int b)
    {
    	return a+b;
    }
    */
    //隐式调用:函数模板会帮助我们自动去推导这个T的类型是什么类型
    //函数模板的类型只有一个任意类型
    //显示指定类型:给函数模板的类型参数,传一个具体的参数(类型),是可以有类型的自动转换的
    int main()
    {
    	cout << fun(1, 2) << endl;//隐式调用
    	cout << fun(1.2, 2.4) << endl;
    	int x = fun('A', 'A');
    	cout << x << endl;//-126----》中间要经过0
    	cout << fun<char>(1, 'A') << endl;//显示指定类型,输出B
    fun<>(1,2)//空参数列表也能强制调用函数模板
        //cout<<fun(1,'a');这样是不行的,必须显示指定类型
        //cout<<fun<int>(1,'a');空参数列表也不行
    	system("pause");
    	return 0;
    }
    

    5、模板的局限性

    //模板在具体使用的过程中还是会出现一些问题
    template<class T>
    bool mycompare(T&a,T&b)
    {
        if(a==b)
        {
            return true;
        }
        return false;
    }
    //这个函数模板在对于基本数据类型的比较是没有太大问题的,但是如果T是一个自定义数据类型,那么就不一定能用==来进行比较,所以在这里我们可以在自定义类型中加上重载运算符==来解决这个问题或者通过一个重载函数来处理
    class person
    {
        public:
        int x;
    }
    //重载函数
    template<>bool mycompare<person>(perosn&a,person&b)
    {
        if(a.x==a.x)
        {
            return true;
        }
        return false;
    }
    
    //解决方法
    #include<iostream>
    using namespace std;
    template<class T>
    bool mycompare(T&a, T&b)
    {
    	if (a == b)
    	{
    		return true;
    	}
    	return false;
    }
    class person
    {
    public:
    	int x;
    };
    struct node
    {
    	int a, b;
    	node()
    	{
    		a = 1, b = 2;
    	}
    
    };
    //在c++中的结构体里面可以写的东西:在类中可以写的,在结构体里面也可以写,比如构造析构
    //因为不能比较两个类
    //解决方法:1.运算符重载==
    //2.通过语法重载解决这个没有compare函数
    //template<>返回值类型 函数名<具体的类型>(具体的类型定义的参数列表)
    //3.单独写个函数比较,不用模板
    template<>bool mycompare<person>(person&a, person&b)
    {
    	if (a.x == b.x)
    		return true;
    	return false;
    
    }
    //重载==
    bool operator==(person& a, person& b)
    {
    	if (a.x == b.x)
    		return true;
    	return false;
    }
    int main()
    {
    	person p1, p2;
    	p1.x = 10;
    	p2.x = 10;
    	cout << mycompare(p1, p2) << endl;
    
    
    	system("pause");
    	return 0;
    }
    

    三、类模板

    1、类模板是什么

    1.类模板与函数模板类似,也不是一个实体的类,理解为一个类的框架

    2、类模板定义

    template<类型参数列表>
    class 类模板名
    {
        成员函数和变量
    }
    

    3、类模板示例

    template<class nametype,class agetype=int>//类模板也可以有默认类型,这是函数缺省
    class person
    {
        public:
        nametype name;
        agetype age;
        person(nametype name,agetype age)//在类模板中直接定义成员函数
        {
            this->name=name;
            this->age=age;
        }
        agetype getage();//在类模板中声明成员函数,在类外定义
    }
    template<class nametype,class agetype>//类模板外定义刚声明的函数
    agetype person<nametype,agetype>::getage()
    {
        return age;
    }
    

    4、类模板--动态数组

    #include<iostream>
    using namespace std;
    template<typename T/*,typename T1,typename T2=int*/>
    //类模板的类型参数同样可以缺省
    class myarr
    {
    	T buff[100];//定义了一个数组
    	int len;
    public:
    	myarr()//构造函数,初始化
    	{
    		memset(buff,0, sizeof(T) * 100);//初始化数组
    		len = 0; 
    	}
    	void insert(int data)
    	{
    		buff[len++] = data;
    	}
    	void print()
    	{
    		for (int i = 0; i < len; i++)
    		{
    			cout << buff[i] << "	";
    		}
    		cout << endl;
    	}
    };
    
    int main()
    {
    	myarr<int> m1;//类模板不支持隐式推导类型,必须使用显示指定类型调用
    	for (int i = 0; i < 10; i++ )
    	{
    		m1.insert(i + 1);
    	}
    	m1.print(); 
    	myarr<char> m2;
    	for (char i = 'a'; i <= 'z'; i++)
    	{
    		m2.insert(i);
    	}
    	m2.print();
    
    	system("pause");
    	return 0;
    }
    

    5、类模板做函数的参数

    1、作为函数的传入实参
    void dowork(perosn<string,int>&p){}
    //把一个具体的类作为函数的参数
    2、参数模板化
    template<class T1,class T2>
    void dowork(perosn<T1,T2>&p){}
    //函数也是模板,且模板中的参数继续给类模板作为参数
    3、整体模板化
    template<class T>
    void dowork(T&p){}
    //可以把perosn<string,int> 整体当成T类型,比如
    //perosn<string,int> myperson;
    //dowork(myperson);
    
    #include<iostream>
    #include<string>
    using namespace std;
    template<class T1,class T2>//定义两个类模板
    class person
    {
    public:
    	T1 name;
    	T2 age;//定义两个类模板里的成员
    	person(T1 name, T2 age)
    	{
    		this->age = age;
    		this->name = name;
    	}
    	void showperson()
    	{
    		cout << name << "	" << age << endl;
    	}
    };
    
    //拿具体的类类型当做形参,来接收实参
    void fun(person<string, int>&p)
    {
    	p.showperson();
    }
    //参数模板化
    template<class T1,class T2>
    void fun1(person<T1, T2>&p)
    {
    	p.showperson();
    }
    //整体模板化
    template<class T>
    void fun2(T&p)
    {
    	p.showperson();
    }
    int main()
    {
    	person<string, int> p1("张飞", 500);
    	p1.showperson();
    	fun(p1);
    	fun1(p1);//可以不写参数
    	fun2(p1);
    	system("pause");
    	return 0;
    }
    

    6、类模板和继承

    #include<iostream>
    #include<string>
    using namespace std;
    template<class T1>
    class base
    {
    public:
    	T1 a;
    };
    template<class T1,class T2>
    class child :public base<T1>
    {
    public:
    	T2 b;
    };
    //如果父类是类模板,那么在定义子类的对象的时候,是需要构造父类的成员的
    //如果父类的这个任意类型T1不知道是什么类型,那么无法定义成员a(无法定义父类的成员),就需要在继承的时候,告诉父类的这个T1是什么类型
    int main()
    {
    	child<int, int> c;
    	
    	system("pause");
    	return 0;
    }
    

    7、类模板不能分模板编写

    1.类模板中成员函数的创建时在调用阶段,那么就会导致在分文件编写的时候链接不到,即不能分文件编写类模板

    2.解决方法,直接将声明和实现写到同一个文件中,把后缀名改为.hpp,.hpp是一个约定俗成的名称

    person.h

    写在同一个文件下面

    #pragma once
    #include<stdio.h>
    template<class T>
    class person
    {
    public:
    	T n;
    	void fun();
    };
    
    template<class T>
    inline void person<T>::fun()
    {
    	printf("aaaa");
    }
    
    

    源.cpp

    #include<iostream>
    #include"person.h"
    using namespace std;
    
    int main()
    {
    	person<int> p;
    	p.fun();
    	
    	system("pause");
    	return 0;
    }
    
    #include<iostream>
    using namespace std;
    class A
    {
    public:
    	void Afun()
    	{
    		cout << "A的fun函数" << endl;
    	}
    };
    class B
    {
    public:
    	void Bfun()
    	{
    		cout << "B的fun函数" << endl;
    	}
    };
    template<class T>
    class CC
    {
    	T t;
    public:
    	void funa()
    	{
    		t.Afun();
    	}
    	void funb()
    	{
    		t.Bfun();
    	}
    	T fun1(T a);
    	void fun2();
    };
    template<class T>
    T CC<T>::fun1(T a)
    {
    	return T;
    }
    template<class T>
    void CC<T>::fun2()
    {
    
    }
    int main()
    {
    	CC<A> c;
    	c.funa();
    	system("pause");
    	return 0;
    }
    

    类模板中实现友元函数

    #include<iostream>
    using namespace std;
    //类模板中实现友元函数
    template<class T>
    class person
    {
    	T id;
    public:
    	friend void print(person<T>&p)
    		cout << p.id << endl;
    	person(T id)//带参构造
    	{
    		this->id = id;
    	}
    };
    int main()
    {
    	person<int> p(99);
    	print(p);
    	system("pause");
    	return 0;
    }
    

    类外实现友元函数---较麻烦

    #include<iostream>
    using namespace std;
    
    //类模板向前声明
    template<class T>
    class person;
    //函数模板向前声明
    template<class T>
    void print(person<T>&p);
    
    template<class T>
    class person
    {
    	T id;
    public:
    	
    	person(T id)//带参构造
    	{
    		this->id = id;
    	}
    	friend void print<>(person<T>&p);
    };
    template<class T>
    void print(person<T>&p)
    {
    	cout << p.id << endl;
    }//这里只是一个逻辑代码
    int main()
    {
    	person<int> p(33);
    	print(p);
    	system("pause");
    	return 0;
    }
    
  • 相关阅读:
    开发环境之Webpack
    开发环境之Nginx
    Winfrom排坑
    Winfrom打包教程(Inno Setup工具)
    博客园美化教程
    开发环境之Tomcat
    IDEA编码时卡顿问题
    学习Spring5源码时所遇到的坑
    docker+jmeter+influx+granfana搭建性能测试监控平台
    Windows10上安装 WSL---Ubuntu
  • 原文地址:https://www.cnblogs.com/Kissfly123/p/14476453.html
Copyright © 2011-2022 走看看