【C++】什么是函数模板/类模板?

简介: 1.什么是函数模板?函数模板简单来说就是一个模板,与函数参数的类型无关,是一个模子,不是真正的函数,实例化的函数会根据实参的类型自动推导类型。

一、函数模板


2a1ed753d51441afb07c6168347b36b8.png

1.什么是函数模板?

函数模板简单来说就是一个模板,与函数参数的类型无关,是一个模子,不是真正的函数,实例化的函数会根据实参的类型自动推导类型。

2.函数模板格式

template<typename T1,typename T2...>
返回值类型 函数名(参数列表)
{}

3.函数模板原理

函数模板是一个模板,并不是真正的函数,它是根据传递过来的实参的类型实例化一个具体的函数,相当于我们将重复的事情交给了编译器来操作。

比如说:

template<typename T>
T Add(const T& a1, const T& a2)
{
    return a1 + a2;
}
int main()
{
    int a = 10, b = 20;
    double c = 3.14,d = 2.11;
    cout << Add(a, b) << endl;
    cout << Add(c, d) << endl;  
    return 0;
}

我们定义了一个加法函数的函数模板,来进行加法操作,函数模板会根据我们传递的实参的类型自动实例化出不同的Add函数,这些函数之间构成函数重载。

4.函数模板实例化

(1)隐式实例化

举一个简单的例子:

在我们定义的函数模板中,只给定一个模板参数类型,但是我们可能会有两个不同的实参类型。

template<typename T>
T Add(const T& a1, const T& a2)
{
    return a1 + a2;
}
int main()
{
    int a = 10;
    double b = 20.3;
    cout << Add(a, b) << endl;
    return 0;
}

对于只有一个类型的函数模板,却同时出现了两种不同类型的实参,编译器就无法确认到底用哪个实参类型实例化了。

解决办法:

int main()
{
    int a = 10;
    double b = 20.3;
    cout << Add((double)a, b) << endl;
  cout << Add(a, (int)b) << endl;
  //可能存在精度丢失的情况
    return 0;
}

隐式类型转换,就可以解决编译器无法识别的情况。

(2)显示实例化

template<typename T>
T Add(const T& a1, const T& a2)
{
    return a1 + a2;
}
int main()
{
    int a = 10;
    double b = 20.3;
    cout << Add(a, b) << endl;
    return 0;
}

对于这个案例,还有一种解决方案:

int main()
{
    int a = 10;
    double b = 20.3;
    cout << Add<int>(a, b) << endl;
    return 0;
}

这样的方法叫做显式实例化,实际生活中,我们很少会遇到需要显式实例化的情况,不过对于下面的情况,就必须要显式实力化。

template<class T>
T* Alloc(int n)
{
    return new T[n];
}
int main()
{
    Alloc<double>(10);
    return 0;
}

在这样的情况下,我们没有使用函数模板类型,所以仅仅传递实参n无法推导T的类型,这种情况下必须要使用显式实例化。

二.类模板

1.类模板定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
  // 类内成员定义
};

2.类模板的实例化

注意:

普通类的类型和类名相同

模板类的类型和类名不同

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可。

类模板名字不是真正的类,而实例化的结果才是真正的类。

比如:

// string类名,string<int>才是类型
string<int> s1;
string<double> s2;

1.不管是类模板还是函数模板,其作用范围就是紧跟着的类/函数。

也就是看{}

2.类模板中函数放在类外进行定义时,需要加模板参数列表

比如:

template<typename T>
class Stack
{
public:
    Stack(size_t capacity = 3);
    void Push(const T& data);   
    // 其他方法...
    ~Stack()
    {
        if (_array)
        {
            delete[]_array;
            _capacity = _size = 0;
        }
    }
private:
    T* _array;
    int _capacity;
    int _size;
};
//缺省参数不能给在函数定义,只能在声明给缺省值
//模板的作用域就是专门给一个函数或者一个类用的
//可以看{}的作用范围是那里,模板的作用范围就是哪里。
template<typename T>
Stack<T>::Stack(size_t capacity)
{
    _array = new T[capacity];
    _capacity = capacity;
    _size = 0;
}
template<typename T>
void Stack<T>::Push(const T& data)
{
    // CheckCapacity();
    _array[_size] = data;
    _size++;
}

函数在类外面进行定义时,需要加类模板的参数列表。


注意:不建议模板实例化出来的函数的声明和定义分离。

注意:不建议模板实例化出来的函数的声明和定义分离。

注意:不建议模板实例化出来的函数的声明和定义分离。


上面的例子仅仅是为了演示。

总结

本文讲述了函数模板和类模板的相关问题。

相关文章
|
3天前
|
存储 编译器 C语言
c++的学习之路:5、类和对象(1)
c++的学习之路:5、类和对象(1)
19 0
|
3天前
|
C++
c++的学习之路:7、类和对象(3)
c++的学习之路:7、类和对象(3)
19 0
|
2天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计
|
2天前
|
编译器 C++
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象
|
6天前
|
存储 安全 C语言
【C++】string类
【C++】string类
|
存储 编译器 Linux
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
|
8天前
|
编译器 C++
标准库中的string类(上)——“C++”
标准库中的string类(上)——“C++”
|
8天前
|
编译器 C++
自从学了C++之后,小雅兰就有对象了!!!(类与对象)(中)——“C++”
自从学了C++之后,小雅兰就有对象了!!!(类与对象)(中)——“C++”
|
8天前
|
存储 编译器 C++
自从学了C++之后,小雅兰就有对象了!!!(类与对象)(上)——“C++”
自从学了C++之后,小雅兰就有对象了!!!(类与对象)(上)——“C++”
|
9天前
|
C++
【C++成长记】C++入门 | 类和对象(下) |Static成员、 友元
【C++成长记】C++入门 | 类和对象(下) |Static成员、 友元

热门文章

最新文章