一、类模板基本语法
template<typename NameType, typename AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
Person<string, int> p1("孙悟空", 999);
}
二、 类模板与函数模板区别
类模板与函数模板区别主要有两点:
- 类模板没有自动类型推导的使用方式
- 类模板在模板参数列表中可以有默认参数
1.无自动推导
//Person p("孙悟空", 1000); ❌,无法用自动类型推导
Person<string, int>p("孙悟空", 1000); //正确,只能用显示指定类型
2.可以有默认参数
// 类模板参数列表设置默认类型(重点在这里)
template<typename NameType = string, typename AgeType = int>
class Person { /* ... */ };
void test01()
{
// 方式1:完整写法
Person<string, int> p1("孙悟空", 999); // 显式指定两个类型
// 方式2:使用默认参数(重点示例)
Person<> p2("猪八戒", 888); // 使用默认的string和int
Person p3("唐僧", 35);
// 方式3:部分使用默认参数
Person<float> p4(3.14f, 100); // AgeType使用默认的int
}
三、类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数创建时机是有区别的:
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
// 类模板成员函数只有在被调用时才会实例化,因此:
// 1. 即使存在错误语法(如未定义变量),只要不调用就不会报错
// 2. 支持模板类型相关的延迟编译特性
例:
template<class T>
class MyClass {
public:
// 这个函数在被调用时才会实例化
void problemFunc() {
cout << undefinedVar << endl; // 故意使用未定义的变量
}
// 这个函数在被调用时才会实例化
void correctFunc(T x) {
cout << "Value: " << x << endl;
}
};
int main() {
MyClass<int> obj;
// obj.problemFunc(); // 如果取消注释,编译时会报错(undefinedVar未声明)
obj.correctFunc(5); // ✔️ 正常编译运行,输出 Value: 5
return 0;
}
四、类模板对象做函数参数
类模板实例化出的对象,向函数传参的方式
类模板允许我们定义通用的类,这些类可以针对不同的数据类型进行实例化。当我们创建一个类模板的实例并将其作为参数传递给函数时,有几种不同的方法可以实现这一点。
一共有三种传入方式:
1. 指定传入的类型 --- 直接显示对象的数据类型
2. 参数模板化 --- 将对象中的参数变为模板进行传递
3. 整个类模板化 --- 将这个对象类型模板化进行传递
template<typename T1, typename T2>
class Person {
public:
Person(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
void showPerson() {
cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}
};
1. 指定传入的类型
//1、指定传入类型
void printPerson1(Person<string, int>&p)
{
p.showPerson();
}
void test01()
{
Person<string, int>p("孙悟空", 100);
printPerson1(p);
}
2. 参数模板化
//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;
}
可通过这个语句来读取模板的参数类型
typeid(T1).name()
3. 整个类模板化
template<class T>
void printPerson3( T &p)
{
p.showPerson();
}
void test03()
{
Person<string, int>p("唐僧", 30);
printPerson3(p);
}
类模板笔记AI完善版
一、类模板基本语法
定义方式
使用template<typename T1, typename T2>
声明模板参数列表,类内可通过T1
、T2
使用模板类型。
template<typename NameType, typename AgeType>
class Person {
public:
Person(NameType name, AgeType age) : m_Name(name), m_Age(age) {}
void showInfo() {
cout << "Name: " << m_Name << ", Age: " << m_Age << endl;
}
private:
NameType m_Name;
AgeType m_Age;
};
// 使用示例
void test01() {
Person<string, int> p1("孙悟空", 999); // 显式指定模板类型
p1.showInfo(); // 输出:Name: 孙悟空, Age: 999
}
关键点
- 类模板的成员函数在类内直接定义时默认为内联函数。
- 类模板的模板参数可以用于成员变量、方法参数、返回类型等。
二、类模板与函数模板的区别
-
无自动类型推导
类模板必须显式指定类型参数,而函数模板可通过参数推导类型。// Person p("唐僧", 35); // ❌ Person<string, int> p2("唐僧", 35); // ✅
-
支持默认模板参数
类模板允许为模板参数设置默认值,函数模板不支持。template<typename NameType = string, typename AgeType = int> class Person { /*...*/ }; void test02() { Person<> p3("猪八戒", 500); // 使用默认的 string 和 int Person<float> p4(3.14f, 100); // NameType=float, AgeType=int(默认) }
默认参数规则
-
默认参数必须从右往左设置,未指定的参数必须使用默认值。
-
// C++17 支持(需确保构造函数能推导类型) Person p5("唐僧", 35); // 推导为 Person<const char*, int>
三、类模板成员函数的创建时机
延迟实例化
类模板的成员函数只有在被调用时才会实例化,未调用的函数即使有语法错误也不会报错。
template<class T>
class MyClass {
public:
void errorFunc() {
cout << undefinedVar << endl; // ❌ 未定义变量(若调用则编译失败)
}
void validFunc(T x) {
cout << x << endl; // ✅ 调用时实例化
}
};
int main() {
MyClass<int> obj;
// obj.errorFunc(); // ❌ 取消注释会导致编译错误
obj.validFunc(10); // ✅ 输出:10
return 0;
}
优点
- 减少编译时间,避免生成无用代码。
- 支持条件编译,例如根据模板参数选择不同实现。
四、类模板对象作为函数参数
三种传递方式:
-
显式指定类型
直接固定参数类型,简单但灵活性低。void printPerson1(Person<string, int>& p) { p.showInfo(); }
-
参数模板化
将类模板参数作为函数模板参数,保持灵活性。template<typename T1, typename T2> void printPerson2(Person<T1, T2>& p) { p.showInfo(); cout << "T1 Type: " << typeid(T1).name() << endl; // 输出类型名称(编译器相关) }
-
整个类模板化
泛化处理,适合需要操作多种类模板的场景。template<typename T> void printPerson3(T& p) { p.showInfo(); // 依赖 T 的接口 }
使用示例
void test03() {
Person<string, int> p("孙悟空", 100);
printPerson1(p); // ✅ 显式指定类型
printPerson2(p); // ✅ 参数模板化
printPerson3(p); // ✅ 整个类模板化
}