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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值