C++ 模板 详细解析

目录

模板定义:

函数模板:

定义语法:

普通函数与函数模板区别:

普通函数与函数模板的调用规则:

局限性:

类模板:

定义:

类模板与函数模板的区别:

类模板对象作函数参数:

类模板与继承:

类模板成员函数类外实现:

类模板份文件实现:

类模板友元函数内外实现:


模板定义:

函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能模板分为函数模板和类模板。

函数模板:

定义语法:

template<typename T>
函数声明或定义

注意:在使用模板时,必须要能够推导出一致的数据类型T;模板必须要确定T的数据类型。其有两种调用方式:自动类型推导和显示指定类型俩种方式。

#include<iostream>
using namespace std;
template<typename T>//声明一个模板,告诉编译器T是一个通用数据类型 
    void myswap(T &a,T &b)
    {
        T temp=a;
        a=b;
        b=temp;
    } 
void test()
{
    int a=1;
    int b=2;
    myswap<int>(a,b);//自动类型推导
    cout<<a<<" "<<b<<endl;
    myswap(a,b);//显示指定类型
    cout<<a<<" "<<b<<endl;

}
template<typename T>
void func()
{
    cout<<"func()"<<endl;
}
int main()
{ 
    func<int>();
    test();
    return 0;
}

普通函数与函数模板区别:

1.普通函数可以发生隐式类型转换
2.函数模板若采用自动类型推导,则不能发生隐式类型转换
3.函数模板若采用显示指定类型,则可以发生隐式转换

普通函数与函数模板的调用规则:

1.如果都可以调用,则优先调用普通函数;
2.可以通过空模板参数列表强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,则优先调用函数模板

#include <iostream>
using namespace std;
void func(int a ,int b)
{
    cout<<"普通函数"<<endl;
}

template<typename T>
void func(T a,T b)
{
    cout<<"函数模板"<<endl;
}

template <typename T>
void func(T a,T b,T c)
{
    cout<<"函数模板重载"<<endl;
}


int main()
{
    int a=10;
    int b=20;
    int c=30;
    func(a,b);//普通函数
    func<>(a,b);//函数模板
    func(a,b,c);//函数模板重载
    char d='c';
    char e='e';
    func(e,d);//函数模板可以实现更好的匹配
    return 0;


}

局限性:

模板函数并不是万能的,特别是对于自定义数据类型,这个时候我们应该使用具体化的函数模板。

#include <iostream>
#include<string>
using namespace std;
class person
{
    public:
    string name;
    int age;
    person(string name,int age)
    {
        this->age=age;
        this->name=name;
    }
};
template<typename T>
bool mycompare(T &a,T &b)
{
    return 0;
}

template<> bool mycompare(person &a,person &b)//具体化函数模板来调用person自定义数据类型
{
    if (a.age==b.age&& a.name==b.name)
    {
        cout<<"相等"<<endl;
        return true;
    }
    else
    {
        cout<<"不相等"<<endl;
        return false;
    }
}

int main()
{
    person p1("张三",20);
    person p2("李四",20);
    bool res=mycompare(p1,p2);
    return 0;
}

类模板:

定义:

template<class T>

类模板与函数模板的区别:

1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数

#include <iostream>
#include<string>
using namespace std;
template<class Nametype,class Agetype=int>//可以有默认参数
class Person
{
    public:
    Person(Nametype name,Agetype age)
    {
       this-> name=name;
       this->age=age;
 
   }
   void print()
   {
       cout<<this->age<<" "<<this->name<<endl;
   }
   Nametype name;
   Agetype age;
};

int main()
{
    Person <string,int> p1("赵四",42);//不能Perosn p("赵四",42);
    Person<string>p2("刘能",40);
    p1.print();
    p2.print();
    return 0;
}

类模板中成员函数的创建时机:普通类的成员函数一开始就被创建,而类模板要在调用时才会创建

类模板对象作函数参数:

1.指定传入类型
2.参数模板化
3.整个类模板化

#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->name=name;
        this->age=age;
    }
    void print()
    {
        cout<<"姓名"<<name<<"年龄"<<age<<endl;
    }
};
void printperson1(Person<string,int>p)//指定传入类型
{
    cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
template<class T>
void printperson2(T p)//整个类模板化
{
    cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
template<class T1,class T2>//参数模板化
void printperson3(Person<T1,T2>p)
{

    cout<<"姓名"<<p.name<<"年龄"<<p.age<<endl;
}
 int main()
 {
     Person<string,int>p1("赵四",43);
     printperson1(p1);
     Person<string ,int>p2("刘能",42);
     printperson2(p2);
     Person<string,int>p3("谢广坤",44);
     printperson3(p3);
     return 0;
 }

类模板与继承:

1.当子类继承的父类是一个模板时,子类在声明的时候,需要指出父类中T的类型
2.如果想要灵活指出父类中T的类型,子类也需要变为类模板

#include<iostream>
#include<string>
using namespace std;
 template<class T>
 class base
 {
     T m;
 };

class son1:public base<int>
{

};

template<class T1,class T2>
class son2:public base<T2>
{
    T1 obj;
};


 int main()
 {
     son1 s1;
     son2<int ,char>s2;
     return 0;
 }

类模板成员函数类外实现:

#include <iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
    public:
    T1 name;
    T2 age; 
    Person(T1 name,T2 age);
    void showperson();
};
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->age=age;
    this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
    cout<<name<<" "<<age<<endl;
}
int main()
{
    Person <string ,int>p("Tom",10);
    p.showperson();
    return 0;

}

类模板分文件实现:

1.直接引用源文件
2.源文件和头文件写一起,成.hpp文件

方法一:

//person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
    public:
    T1 name;
    T2 age;
    Person(T1 name,T2 age);
    void showperson();
};
//person.cpp
#include "person.h"
#include<iostream>
using namespace std;
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->age=age;
    this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
    cout<<name<<" "<<age<<endl;
}
#include<iostream>
#include"person.cpp"
using namespace std;

int main()
{
    Person <string ,int>p("Jack",10);
    p.showperson();
    return 0;

} 

方法二:

//person.hpp

#pragma once
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person
{
    public:
    T1 name;
    T2 age;
    Person(T1 name,T2 age);
    void showperson();
};

template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->age=age;
    this->name=name;
}
template<class T1,class T2>
void Person<T1,T2>::showperson()
{
    cout<<name<<" "<<age<<endl;
}
#include<iostream>
#include"person.hpp"
using namespace std;

int main()
{
    Person <string ,int>p("Jack",10);
    p.showperson();
    return 0;

} 

类模板友元函数内外实现:

另外,还有类模板友元函数的类内类外实现,类内友元函数实现和上面的一样,照猫画虎而已,但类外实现有些许复杂。

#include <iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class Person;
template<class T1,class T2>
void print_person2(Person<T1,T2>p)
{
    cout<<p.name<<" "<<p.age<<endl;
}
template <class T1,class T2>
class Person
{
    friend void print_person1(Person<T1,T2> p)//类内实现
    {
        cout<<p.name<<" "<<p.age<<endl;
    }
    public:
    Person(T1 name ,T2 age)
    {
        this->name=name;
        this->age=age;
    }
    friend void print_person2<>(Person<T1,T2>p);//类外实现,需要加载空模板参数列表,而且需要让编译器提前知道这个函数的存在
    private:
    T1 name;
    T2 age;
};

void test01()
{
    Person<string ,int>p1("Tom",10);
    print_person1(p1);
}
void test02()
{
    Person <string ,int>p2("Jack",6);
    print_person2(p2);
}
int main()
{
    test01();
    test02();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值