cpp自学 day22(类模板01)

一、类模板基本语法

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. 类模板没有自动类型推导的使用方式
  2. 类模板在模板参数列表中可以有默认参数

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. 类模板中的成员函数在调用时才创建

// 类模板成员函数只有在被调用时才会实例化,因此:
// 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> 声明模板参数列表,类内可通过 T1T2 使用模板类型。

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
}

​关键点​

  • 类模板的成员函数在类内直接定义时默认为内联函数。
  • 类模板的模板参数可以用于成员变量、方法参数、返回类型等。

二、类模板与函数模板的区别
  1. ​无自动类型推导​
    类模板必须显式指定类型参数,而函数模板可通过参数推导类型。

    // Person p("唐僧", 35);         // ❌ 
    Person<string, int> p2("唐僧", 35); // ✅
  2. ​支持默认模板参数​
    类模板允许为模板参数设置默认值,函数模板不支持。

    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;
}

​优点​

  • 减少编译时间,避免生成无用代码。
  • 支持条件编译,例如根据模板参数选择不同实现。

四、类模板对象作为函数参数

三种传递方式:

  1. ​显式指定类型​
    直接固定参数类型,简单但灵活性低。

    void printPerson1(Person<string, int>& p) {
        p.showInfo();
    }
  2. ​参数模板化​
    将类模板参数作为函数模板参数,保持灵活性。

    template<typename T1, typename T2>
    void printPerson2(Person<T1, T2>& p) {
        p.showInfo();
        cout << "T1 Type: " << typeid(T1).name() << endl;  // 输出类型名称(编译器相关)
    }
  3. ​整个类模板化​
    泛化处理,适合需要操作多种类模板的场景。

    template<typename T>
    void printPerson3(T& p) {
        p.showInfo();  // 依赖 T 的接口
    }

​使用示例​

void test03() {
    Person<string, int> p("孙悟空", 100);
    printPerson1(p);    // ✅ 显式指定类型
    printPerson2(p);    // ✅ 参数模板化
    printPerson3(p);    // ✅ 整个类模板化
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值