C++:模板

系列文章目录

C++内存存储模型

C++引用以及函数的占位、重载

C++封装与对象特性C

C++对象特性及友元

C++运算符重载及继承

C++多态

C++文件操作

C++模板


 文章目录

前言

一、函数模板

1.基本语法

2.数组排序案例

3.普通函数与函数模板的区别

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

5.总结

二、类模板

1.基本语法

2.类模板中成员函数创建时机

3.类模板对象做函数参数

4.类模板与继承

5.类模板成员函数的类外实现

 6.类模板与友元

总结


前言

  • C++ 的模板是一种特性,允许程序员创建泛型代码,可以处理多种数据类型。模板可以应用于函数(称为函数模板)和类(称为类模板)
  • C++ 提供两种模板机制:函数模板类模板

一、函数模板

1.基本语法

函数模板的定义以关键字 template 开始,后面跟着模板参数列表,这个列表是在尖括号 < > 中的一个或多个模板参数。

template <typename T>
T add(T a, T b)
{
    return a + b;
}

2.数组排序案例

template <class T>
void mysort(T buf[], int len)
{
    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < len - i - 1; j++)
        {
            if (buf[j] > buf[j + 1])
            {
                T temp = buf[j];
                buf[j] = buf[j + 1];
                buf[j + 1] = temp;
            }
        }
    }
}

template <class T>
void print(T buf, int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << buf[i] << " ";
    }
    cout << endl;
}

void test01()
{
    char buf[] = "adsfe";
    int len = sizeof(buf) / sizeof(buf[0]);
    mysort(buf, len);
    print(buf, len);
}

void test02()
{
    int buf[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0};
    int len = sizeof(buf) / sizeof(buf[0]);
    mysort(buf, len);
    print(buf, len);
}

3.普通函数与函数模板的区别

  1. 泛型性:普通函数通常对特定类型的参数进行操作,而函数模板可以对多种类型的参数进行操作。函数模板是泛型的,可以用于创建处理不同数据类型的函数。
  2. 定义方式:普通函数的定义与我们通常看到的函数定义相同。函数模板的定义以 template 关键字开始,后面跟着模板参数列表。
  3. 编译时机:普通函数在编译时会生成机器代码。函数模板在编译时不会生成任何代码,只有当模板被实例化(即使用特定类型调用模板)时,才会生成代码。
  4. 调用方式:普通函数可以直接通过函数名调用。函数模板可以通过函数名直接调用,也可以在函数名后面加上尖括号和具体的类型来调用。

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

  • 如果函数模板和普通函数都可以实现,优先调用普通函数
  • 可以通过空模板参数列表来强制调用函数模板
  • 函数模板也可以发生重载
  • 如果函数模板可以产生更好的匹配,优先调用函数模板
void myPrint(int a, int b)
{
    cout << "调用的普通函数" << endl;
}

template<class T>
void myPrint(T a, T b)
{
    cout << "调用的函数模板" << endl;
}

template<class T>
void myPrint(T a, T b, T c)
{
    cout << "调用重载的函数模板" << endl;
}

void test01()
{
    int a = 10;
    int b = 20;
    //myPrint(a, b); //调用普通函数
    myPrint<>(a, b); //强制调用函数模板
    myPrint(a, b, 100); //调用重载的函数模板
}

5.总结

  • 函数模板利用关键字template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

二、类模板

1.基本语法

//类模板
template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << "name:" << this->m_Name << " age:" << this->m_Age << endl;
    }
    T1 m_Name;
    T2 m_Age;
};

void test01()
{
    Person<string, int>p("Tom", 20);
    p.showPerson();
}

2.类模板中成员函数创建时机

在 C++ 中,类模板的成员函数并不是在类模板定义时就立即创建的,而是在我们实例化模板类并使用这些成员函数时才创建的。这种方式的好处是,编译器只会为我们实际使用的类型生成函数,不会为所有可能的类型生成函数,这可以节省编译时间和生成的代码的大小。但是,这也意味着如果我们的代码中有一些错误,只有在实际使用模板类时才会被发现。

3.类模板对象做函数参数

共有三种传入方式

  • 指定传入的类型
  • 参数模板化
  • 整个类模板化
//类模板对象做函数参数
template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        cout << "name:" << this->m_Name << " age:" << this->m_Age << endl;
    }
    T1 m_Name;
    T2 m_Age;
};

//1、指定传入类型
void printPerson1(Person<string, int>& p)
{
    p.showPerson();
}

void test01()
{
    Person<string, int>p("Tom", 20);
    printPerson1(p);
}

//2、参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
    p.showPerson();
    cout << "T1的类型为:" << typeid(T1).name() << endl;
    cout << "T2的类型为:" << typeid(T2).name() << endl;
}

void test02()
{
    Person<string, int>p("Jerry", 30);
    printPerson2(p);
}

//3、整个类模板化
template<class T>
void printPerson3(T& p)
{
    p.showPerson();
    cout << "T的类型为:" << typeid(T).name() << endl;
}

void test03()
{
    Person<string, int>p("Jerry", 30);
    printPerson3(p);
}

4.类模板与继承

在 C++ 中,类模板可以被继承,就像普通的类一样。但是,当子类继承的父类是一个类模板时,子类在声明的时候,需要指定父类模板参数的类型。如果不指定,编译器无法给子类分配内存。

//类模板的继承
//当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
//如果不指定,编译器无法给子类分配内存
template<class T>
class Base
{
    T m;
};

//class Son :public Base //错误的
class Son :public Base<int>
{

};

void test01()
{
    Son s1;
}

//如果想灵活指定出父类中T的类型,子类也需变为类模板
template<class T1, class T2>
class Son2 :public Base<T2>
{
    T1 obj;
};

void test02()
{
    Son2<int, char> s2;
}

5.类模板成员函数的类外实现

//类模板成员函数的类外实现
template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age);
    void showPerson();
    T1 m_Name;
    T2 m_Age;
};

//构造函数类外实现
template<class T1, class T2>
Person<T1, T2> :: Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

//成员函数类外实现
template<class T1, class T2>
void Person<T1, T2> :: showPerson()
{
    cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}

void test01()
{
    Person<string, int> p("Tom", 20);
    p.showPerson();
}

 6.类模板与友元

  • 全局函数类内实现-直接在类内声明友元即可
  • 全局函数类外实现-需要提前让编译器知道全局函数的存在
template<class T1, class T2>
class Person;

//类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2> &p)
{
    cout << "类外实现 -- 姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
    //全局函数 类内实现
    friend void printPerson(Person<T1, T2> &p)
    {
        cout << "类内实现 -- 姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
    }

    //全局函数 类外实现
    friend void printPerson2<>(Person<T1, T2> &p);

public:
    string m_Name;
    int m_Age;
};

void test01()
{
    Person<string, int> p;
    p.m_Name = "Tom";
    p.m_Age = 18;
    printPerson(p);

    printPerson2(p);
}

总结

  • 函数模板:函数模板是一种特殊的函数,可以处理不同类型的数据。你可以将数据类型作为参数传递给模板,编译器会根据传递的数据类型生成相应的函数。

  • 类模板:类模板是一种特殊的类,可以处理不同类型的数据。你可以将数据类型作为参数传递给模板,编译器会根据传递的数据类型生成相应的类。

  • 模板参数:模板参数可以是类型参数,也可以是非类型参数。类型参数表示的是类型,非类型参数表示的是值。

  • 模板特化:模板特化是一种特殊的模板,它为特定的类型或值提供特殊的实现。

  • 模板的实例化:模板的实例化是在编译时根据模板生成具体代码的过程。编译器会根据模板参数的类型或值生成相应的函数或类。

  • 模板的调用规则:当普通函数和模板函数都可以处理某个函数调用时,编译器会优先选择普通函数。

  • 模板与友元:类模板可以有友元函数。在定义友元函数时,需要使用 template 关键字和模板参数列表,并在函数名前使用类模板名和模板参数列表。

  • 类模板的继承:类模板可以被继承,子类在声明时需要指定父类模板参数的类型。

  • 类模板成员函数的类外实现:类模板的成员函数可以在类外部定义,需要在函数定义前使用 template 关键字和模板参数列表,并在函数名前使用类模板名和模板参数列表。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值