类模板
内容简介
类模板用于定义类型可变的类。STL 容器就是最典型的类模板,例如 std::vector<int>、std::map<std::string, int>。
用法
基本语法:
template <typename Name, typename Age>
class Person {
public:
Person(Name name, Age age)
: name_(name), age_(age)
{
}
void show() const
{
std::cout << name_ << " " << age_ << '\n';
}
private:
Name name_;
Age age_;
};使用方式:
Person<std::string, int> p("Alice", 18);
p.show();类模板和函数模板的区别
类模板通常需要显式指定类型
Person<std::string, int> p("Alice", 18);旧标准中类模板没有自动类型推导。C++17 起有 CTAD,但初学阶段建议先显式写清类型。
类模板可以有默认模板参数
template <typename Name, typename Age = int>
class Person {
public:
Person(Name name, Age age) : name_(name), age_(age) {}
private:
Name name_;
Age age_;
};
Person<std::string> p("Bob", 20);类模板成员函数调用时机
类模板的成员函数通常在被使用时才实例化。
class Person1 {
public:
void show1() {}
};
class Person2 {
public:
void show2() {}
};
template <typename T>
class MyClass {
public:
T obj;
void func1()
{
obj.show1();
}
void func2()
{
obj.show2();
}
};
MyClass<Person1> m;
m.func1(); // 正确
// m.func2(); // 错误:Person1 没有 show2,但只有调用 func2 时才暴露类模板对象做函数参数
直接指定类型:
void print_person(Person<std::string, int>& p)
{
p.show();
}参数模板化:
template <typename Name, typename Age>
void print_person(Person<Name, Age>& p)
{
p.show();
}整个类型模板化:
template <typename T>
void print_any(T& value)
{
value.show();
}类模板与继承
继承类模板时,父类模板参数必须能确定:
template <typename T>
class Base {
T value_;
};
class Son : public Base<int> {
};
template <typename T1, typename T2>
class Son2 : public Base<T2> {
T1 obj_;
};最佳代码实践
- 类模板适合保存或处理“类型可变但结构一致”的对象。
- 模板参数名称要表达含义,不要所有参数都叫
T1、T2。 - 能用标准库类模板时优先用标准库,例如
std::vector、std::optional、std::unique_ptr。 - 初学阶段显式写模板实参,熟悉后再使用 CTAD。
错误用法
Person p("Alice", 18); // C++17 前错误;初学阶段也不建议依赖推导template <typename T>
class Box {
T value_;
};
Box box; // 错误:无法知道 T 是什么注意事项
- 类模板实例化后才是真正的类型。
Person<std::string, int>和Person<std::string, double>是不同类型。- 类模板成员函数分文件写法要特别小心,见 cpp类模板分文件编写。