感谢哔哩哔哩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;
}