感谢哔哩哔哩UP”开发者LaoJ“,以下是听课记录~
模板是C++实现泛型编程的手段,同一段代码逻辑可以接受多个类型的参数
无论是函数模板还是类模板,在编码后,需要分文件时,将其声明和定义放进.hpp文件中。不要将声明放.h,定义放.cpp,会报错
一、函数模板
对于函数模板,使用不同的类型对其进行实例化时,会生成多个不同的函数
当没有调用函数模板时,不会被实例化(延迟实例化)
1.1、接受类型参数
#include <iostream>
#include <string>
using namespace std;template <typename T>
void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
/*允许为特定的数据类型提供定制的实现*当类型为int时,调用的是以下实现,而不是函数模板中的实现*/
void Swap(int& a, int& b)
{int tmp = a;a = 2 * b;b = 2 * tmp;
}int main(void)
{int val1 = 10, val2 = 20;cout << val1 << " " << val2 << endl;/*函数模板有自动推导*Swap<int>(val1, val2)与Swap(val1, val2)等价*/Swap<int>(val1, val2);cout << val1 << " " << val2 << endl;double d1 = 3.14, d2 = 6.78;cout << d1 << " " << d2 << endl;Swap(d1, d2);cout << d1 << " " << d2 << endl;return 0;
}
1.2、接受非类型参数作为常量
#include <iostream>
#include <string>
using namespace std;template <int N>
void printNTimes(const string& str)
{for (int i = 0; i < N; ++i)cout << str << endl;
}int main(void)
{string str = "hello world!";printNTimes<5>(str);
}
二、类模板
2.1、类模板
类模板的类型参数可以有默认值(默认值从右到左,不能出现右边的没有默认值而左边的有默认值)
类模板没有自动推导的使用方式(在创建类对象时,必须显式说明类型)
/*没有自动推导方式*/
template<typename T1, typename T2>
clase myclass
{
public:myclass(T1 name, T2 age) : name(name), age(age) {}
private:T1 name;T2 age;
};myclass<string, int> obj("lisi", 20); //正确
myclass obj("lisi", 20); //错误,要显示说明类型/*默认值*/
template<typename T1, typename T2 = int> //正确,可以有默认值
template<typename T1 = string, typename T2> //错误,默认值应该从右到左
2.1.1、模板类在调用时,才会被实例化
#include<iostream>
using namespace std;class me
{
public:void showme() {cout << "This is me" << endl;}
};template <typename T>
class myclass
{
public:void test() {T obj;obj.showme(); //未定义}
};int main(void)
{myclass<me> obj;obj.test();return 0;
}
2.1.2、在模板类内声明函数,在类外定义函数
#include<iostream>
using namespace std;class me
{
public:void showme() {cout << "This is me" << endl;}
};template <typename T>
class myclass
{
public:void test();
};/*函数在类外进行定义*/
template <typename T>
void myclass<T>::test() {T obj;obj.showme();
}int main(void)
{myclass<me> obj;obj.test();return 0;
}
2.1.3、当模板类作为函数参数时
#include<iostream>
#include<string>
using namespace std;template <typename T1, typename T2>
class myclass
{
public:myclass(T1 name, T2 age) : name(name), age(age) {}void showme() {cout << "name:" << name << " " << "age:" << age << endl;}
private:T1 name;T2 age;
};/*方法一:确定具体的类型传入*/
void func1(myclass<string, int> obj)
{obj.showme();
}/*方法二:参数模板化*/
template <typename T1, typename T2>
void func2(myclass<T1, T2> obj)
{obj.showme();
}/*方法三:将类模板化*/
template <typename T>
void func3(T& obj)
{obj.showme();
}int main(void)
{myclass<string, int> obj("lisi", 20);func1(obj);func2(obj);func2(obj);return 0;
}
2.2、类模板与继承
#include <iostream>
using namespace std;/*基类是模板类*/
template <typename T>
class Base {
public:Base(T value) : data(value) {}void show() {cout << "Base data: " << data << endl;}
protected:T data;
};/*情况一:派生类不是模板类*/
//方法一:派生类继承模板基类的特化版本(例如 int)
class DerivedInt : public Base<int> {
public:DerivedInt(int value) : Base<int>(value) {} //在此处,调用了Base<int>类的构造函数void display() {cout << "DerivedInt data: " << data << endl;}
};
//方法二:派生类继承模板基类(仍然是模板)
template <typename T>
class DerivedTemplate : public Base<T> {
public:DerivedTemplate(T value) : Base<T>(value) {}void display() {cout << "DerivedTemplate data: " << this->data << endl;}
};/*情况二:派生类是模板类*/
template <typename T, typename U>
class Derived : public Base<T> {
public:Derived(T baseValue, U derivedValue) : Base<T>(baseValue), extraData(derivedValue) {}void display() {cout << "Base data: " << this->data << ", Derived data: " << extraData << endl;}
private:U extraData;
};int main() {/*对于情况一*/DerivedInt obj1(10);obj1.show();obj1.display();DerivedTemplate<double> obj2(3.14);obj2.show();obj2.display();/*对于情况二*/Derived<int, double> obj3(10, 3.14);obj3.show(); // 调用基类方法obj3.display(); // 调用派生类方法return 0;
}
2.3、友元函数与模板类
#include <iostream>
#include <string>
using namespace std;// 前向声明模板类和函数print
template <typename T1, typename T2>
class Base;
template <typename T1, typename T2>
void print(Base<T1, T2>& obj);template <typename T1, typename T2>
class Base {
public:Base(T1 name, T2 age) : name(name), age(age) {}/*在类内定义友元函数*/friend void show(Base<T1, T2>& obj) {cout << "show:" << endl;cout << "name:" << obj.name << " " << "age:" << obj.age << endl;}friend void print<T1, T2>(Base<T1, T2>& obj);
private:T1 name;T2 age;
};/*在类外定义友元函数*一、需要向前声明模板类和友元函数*二、在类中声明友元函数*三、在类外定义友元函数*/
template <typename T1, typename T2>
void print(Base<T1, T2>& obj) {cout << "print: " << endl;cout << "name:" << obj.name << " " << "age:" << obj.age << endl;
}int main(void) {Base<string, int> obj("lisi", 20);show(obj);print(obj);return 0;
}