C++模板 - 模板的使用

简介: C++模板 - 模板的使用

C++模板


C++提供了函数模板:所谓的函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需要在模板中定义一次即可。在调用函数时系统会根据实参类型来取代模板中的虚拟类型,从而实现不同函数的功能。C++提供了两种模板机制:类模板和函数模板


模板把函数或者类要处理的数据类型参数化,表现为参数的多态性,称为类属。模板用于表达逻辑结构相同,但具体数据元素不同的数据对象的通用行为


函数模板


示例代码

#include <iostream>
#include <string>

template<typename T>
auto testSwap(T &a, T &b) -> void
{
    T tmp = a;
    a = b;
    b = tmp;
}

int main(int argc, char* argv[])
{
    int a = 10; int b = 20;
    // 自动推导类型
    testSwap(a, b);
    std::cout << a << " " << b << std::endl;
    std::string aa = "aaa", bb = "bbb";
    testSwap(aa, bb);
    std::cout << aa << " " << bb << std::endl;
    // 显示指定类型
    int c = 30; int d = 40;
    testSwap<int>(c, d);
    std::cout << c << " " << d << std::endl;
    return 0;
}


函数模板和普通函数区别


你可以使用以下代码来测试调用顺序

#include <iostream>
#include <string>

template<typename T>
auto testSwap(T &a, T &b) -> void
{
    std::cout << "函数模板" << std::endl;
    T tmp = a;
    a = b;
    b = tmp;
}
auto testSwap(int &a, int &b) -> void
{
    std::cout << "普通函数" << std::endl;
    int tmp = a;
    a = b;
    b = tmp;
}

int main(int argc, char* argv[])
{
    int a = 10; int b = 20;
    testSwap(a, b);
    std::cout << a << " " << b << std::endl;
    std::string aa = "aaa", bb = "bbb";
    testSwap(aa, bb);
    std::cout << aa << " " << bb << std::endl;

    int c = 30; int d = 40;
    testSwap<int>(c, d);
    std::cout << c << " " << d << std::endl;
    return 0;
}


  • 函数模板和普通函数都识别的时候,优先调用普通函数,但是指定模板类型的时候是调用函数模板的。

执行下面代码:注释放开和不放开时候试试

template<typename T>
auto testSwap(T a, T b) -> void
{
    std::cout << "函数模板" << std::endl;
}
//auto testSwap(int a, int b) -> void
//{
//    std::cout << "普通函数" << std::endl;
//}

int main(int argc, char* argv[])
{
    int a = 30; char b = 'a';
//     testSwap(a, b);
    testSwap<int>(a, b);
    return 0;
}


  • 函数模板的参数类型不能自动转换
  • 函数模板也可以重载


函数模板的局限性


如果代码定义了赋值操作a=b, 但是T为数组,这种假设就不成立了,同样的,如果里面的语句为判断语句 if(a>b),但是T如果有结构体,该假设也不成立,另外如果传入的是数组,数组名为地址,因此比较的是地址,而这也不是我们需要的操作。总之编写函数模板无法处理某些类型。另一方面,有时候通用化是有意义的,但是C++不允许这么做。为了解决这种问题,可以提供模板的重载为这些特定的类型提供具体化的模板。

#include <iostream>
#include <string>

using namespace std;

template<typename T>
auto testSwap(T &a, T &b) -> void
{
    T tmp = a;
    a = b;
    b = tmp;
}

class Person
{
public:
    Person() {}
    Person(const Person &other) = delete;
    void operator=(const Person& out) = delete;

    friend ostream& operator<<(ostream& out, const Person&p)
    {
        return out << "(" << p.age << "," << p.name << ")";
    }

    int age;
    std::string name;
};

int main(int argc, char* argv[])
{
    Person p1; Person p2;
    p1.age = 10;
    p1.name = "aaa";
    p2.age = 20;
    p2.name = "bbb";
    testSwap(p1, p2);

    std::cout << p1 << p2 << std::endl;
    return 0;
}

上述代码会报错。


类模板


示例代码

#include <iostream>
#include <string>

using namespace std;

template<typename T, typename U>
class Data
{
public:
    Data(const T &t, const U &u)
    {
        this->name = t;
        this->num = u;
        cout << "有参构造" << endl;
    }
    ~Data()
    {
        cout << "析构函数" << endl;
    }

    void showPerson()
    {
        std::cout << this->name << " " << this->num << endl;
    }

private:
    T name;
    U num;
};

int main(int argc, char* argv[])
{
    Data<string, int> data("aa", 5);
    data.showPerson();
    Data<string, int> data2("bb", 6);
    data2.showPerson();
    return 0;
}


类模板做函数参数

void test(Data<string, int> &p)
{
    p.showPerson();
}


类模板派生普通类


类模板派生普通类的时候必须指定类型,否则无法派生

#include <iostream>
#include <string>
using namespace std;
template<class T>
class Base
{
public:
    Base(const T &t) : name(t){}
    T name;
};
class Derive : public Base<string>
{
public:
    Derive(const string &s) : Base<string>(s){}
};
int main(int argc, char* argv[])
{
    Derive d("张三");
    std::cout << d.name << std::endl;
    return 0;
}


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


类模板的作用域是Class<T>

#include <iostream>
#include <string>
using namespace std;
template<class T1, class T2>
class Person
{
public:
    Person(const T1&t, const T2 &t2) ;
    void showPerson();

    T1 name;
    T2 name2;
};
template<class T1, class T2>
Person<T1, T2>::Person(const T1 &t, const T2 &t2)
    : name(t)
    , name2(t2)
{
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    std::cout << name << " " << name2 << endl;
}
int main(int argc, char* argv[])
{
    Person<int, int> a(10, 10);
    a.showPerson();
    return 0;
}


模板类的类型是 Person<T1, T2>


类模板头文件和源文件分离


类模板会经过两次编译,第一次是类模板本身的编译,第二次是在函数在调用的时候编译,确定对应的类型


C/C++都是独立文件编译,因此第二次的编译的时候会替换对应的文件,但是因为没有包含对应的cpp,因此无法获取到对应的实现,因此没有定义过程,因为我们正常不包含cpp,所以模板类的实现和声明放在一个文件内

// person.h
#ifndef ALGOTEST_PERSON_H
#define ALGOTEST_PERSON_H
template<class T1, class T2>
class Person
{
public:
    Person(const T1&t, const T2 &t2) ;
    void showPerson();
    T1 name;
    T2 name2;
};
#endif //ALGOTEST_PERSON_
// person.cpp
#include "person.h"
#include <iostream>
using namespace std;
template<class T1, class T2>
Person<T1, T2>::Person(const T1 &t, const T2 &t2)
        : name(t)
        , name2(t2)
{
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << name << " " << name2 << endl;
}
// person.hpp
#ifndef ALGOTEST_PERSON_HPP
#define ALGOTEST_PERSON_HPP
#include <iostream>
template<class T1, class T2>
class Person
{
public:
    Person(const T1&t, const T2 &t2) ;
    void showPerson();
    T1 name;
    T2 name2;
};
using namespace std;
template<class T1, class T2>
Person<T1, T2>::Person(const T1 &t, const T2 &t2)
        : name(t)
        , name2(t2)
{
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << name << " " << name2 << endl;
}
#endif //ALGOTEST_PERSON_HPP


模板的应用


实现一个简单的vector

目录
相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
122 10
|
4月前
|
编译器 C++
【C++】——初识模板
【C++】——初识模板
【C++】——初识模板
|
1月前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
50 4
|
1月前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
36 3
|
5月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
1月前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
33 0
|
2月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
20 1
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
50 9
|
2月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
70 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
96 2