cpp自学 day23(类模板02)

一、类模板与继承

当类模板碰到继承时,需要注意一下几点:

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也需变为类模板

1.子类在声明的时指出父类中T的类型

template<class T>
class Base
{
    T m;
};

// class Son : public Base //❌,必须要知道父类中的T类型,才能继承给子类
class Son : public Base<int>
{
};

2.子类灵活指定父类T类型

 首先,我们定义了一个基类模板 Base,它有一个类型参数 T

template<class T>
class Base
{
    T m;
};

        这个基类模板 Base 有一个成员变量 m,其类型由模板参数 T 决定。

接下来,我们定义了一个子类模板 Son2,它继承自 Base 类模板。这里的关键是,Son2 也是一个模板类,它有两个类型参数 T1T2。在继承 Base 时,我们指定 Base 的模板参数为 T2,这样 Son2 就可以灵活地为 Base 指定类型参数了。

template<class T1, class T2>
class Son2 : public Base<T2>
{
    T1 obj;
};

在这个子类模板 Son2 中:

  • T1Son2 自己的类型参数,用于 Son2 类内部的成员变量 obj

  • T2Son2 的另一个类型参数,用于指定继承自 BaseBase 的模板参数。

最后,我们定义了一个函数 test02,用于创建 Son2 的实例。在这个函数中,我们实例化 Son2 时指定了两个类型参数 intchar

void test02()
{
    Son2<int, char> S2;
}

这里的 Son2<int, char> 表示:

  • intSon2T1 类型参数,用于 obj 成员变量。

  • charSon2T2 类型参数,用于指定 Base 的模板参数。

这样,S2 实例的 obj 成员变量将是 int 类型,而它继承自 Base 的成员变量 m 将是 char 类型。


二、类模板成员函数类外实现

template<class T1, class T2>
class Person {
public:
    // 成员函数类内声明
    Person(T1 name, T2 age);
    void showPerson();

public:
    T1 m_Name;
    T2 m_Age;
};

成员函数类外实现

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
    cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << endl;
}

构造函数类外实现

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

三、类模板分文件编写

掌握类模板成员函数分文件编写产生的问题以及解决方式

问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

  • 解决方式1:直接包含.cpp源文件

  • 解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称,并不是强制

ps★:其实这里的问题是在前面类模板中成员函数创建时机时所牵扯下的问题,详情请看day22,感觉这里.hpp真好用


四、类模板与友元

学习目标:

        掌握类模板配合友元函数的类内和类外实现

  •         全局函数类内实现 - 直接在类内声明友元即可
  •         全局函数类外实现 - 需要提前让编译器知道全局函数的存在
 代码基础结构
template<class T1, class T2>
class Person {
public:
    T1 m_Name;  // 姓名(模板类型)
    T2 m_Age;   // 年龄(模板类型)

    // 构造函数
    Person(T1 name, T2 age) {
        this->m_Name = name;  // this-> 访问成员
        this->m_Age = age;
    }
};
类内实现(直接定义)​

​特点​​:直接在类内声明并定义友元函数,无需额外模板声明。

template<class T1, class T2>
class Person {
/***/
public:
    // 友元函数直接在类内定义
    friend void printPerson(Person<T1, T2> p) {
        cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
    }
/***/
};
类外实现(需分步声明)​

​特点​​:函数在类外定义,需提前声明模板类和函数,解决编译依赖问题。

步骤说明​​:
  1. ​前向声明模板类​​:告知编译器 Person 类的存在。
  2. ​声明全局函数模板​​:提前声明函数模板。
  3. ​类内声明友元关系​​:在类内绑定友元函数。
  4. ​类外实现函数​​:在类外完成具体逻辑。
// 1. 前向声明模板类
template<class T1, class T2>
class Person;

// 2. 声明全局函数模板
template<class T1, class T2>
void printPerson2(Person<T1, T2> p);

// 3. 类内声明友元关系
template<class T1, class T2>
class Person {
public:
    // 友元函数声明(关联类外实现的模板函数)
    friend void printPerson2<>(Person<T1, T2> p);

    // 构造函数
    Person(T1 name, T2 age) : m_Name(name), m_Age(age) {}

private:
    T1 m_Name;
    T2 m_Age;
};

// 4. 类外实现函数
template<class T1, class T2>
void printPerson2(Person<T1, T2> p) {
    cout << "类外实现---姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}

AI版笔记​


​一、类模板与继承​
​1. 明确父类模板类型​

子类继承模板父类时,​​必须指定父类的模板参数类型​​,否则编译器无法分配内存:

template<class T>
class Base {
public:
    T m;  // 成员变量类型由T决定
};

// ✅ 正确:子类指定父类模板类型为int
class Son : public Base<int> { 
    // 子类逻辑...
};
​2. 子类作为模板继承父类​

若希望子类能灵活指定父类模板类型,需将子类也定义为模板:

template<class T1, class T2>
class Son2 : public Base<T2> {  // 父类类型由T2决定
public:
    T1 obj;  // 子类自定义成员类型
};

// 使用示例
void test() {
    Son2<int, char> s;  // s.obj为int,继承的Base成员m为char
}

​二、类模板成员函数类外实现​
​1. 成员函数定义语法​

类外实现时需​​显式声明模板参数​​,并使用类作用域运算符::

template<class T1, class T2>
class Person {
public:
    Person(T1 name, T2 age);  // 构造函数声明
    void showPerson();        // 成员函数声明
private:
    T1 m_Name;
    T2 m_Age;
};

// 构造函数类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) : m_Name(name), m_Age(age) {}

// 成员函数类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
    cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}

​三、类模板分文件编写​
​1. 问题与解决方案​
  • ​问题​​:类模板成员函数的代码在编译时实例化,若分文件为.cpp.h会导致链接错误。
  • ​解决​​:​​将声明和实现统一写在.hpp文件​​中(约定俗成的模板文件扩展名):
// Person.hpp
#pragma once
#include <iostream>
using namespace std;

template<class T1, class T2>
class Person {
public:
    Person(T1 name, T2 age);
    void showPerson();
private:
    T1 m_Name;
    T2 m_Age;
};

// 成员函数直接在.hpp中实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) : m_Name(name), m_Age(age) {}

template<class T1, class T2>
void Person<T1, T2>::showPerson() {
    cout << "姓名:" << m_Name << " 年龄:" << m_Age << endl;
}

​四、类模板与友元函数​
​1. 友元函数类内实现​

直接在类内声明并定义友元函数,无需额外模板声明:

template<class T1, class T2>
class Person {
public:
    // 友元函数类内实现(直接访问私有成员)
    friend void printPerson(Person<T1, T2> p) {
        cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
    }

    Person(T1 name, T2 age) : m_Name(name), m_Age(age) {}

private:
    T1 m_Name;
    T2 m_Age;
};
​2. 友元函数类外实现​

需分步处理依赖关系:

// 1. 前向声明模板类
template<class T1, class T2>
class Person;

// 2. 声明全局函数模板
template<class T1, class T2>
void printPerson2(Person<T1, T2> p);

// 3. 类内声明友元关系(空模板参数<>表示匹配已声明的函数模板)
template<class T1, class T2>
class Person {
public:
    friend void printPerson2<>(Person<T1, T2> p);  // 注意<>
    
    Person(T1 name, T2 age) : m_Name(name), m_Age(age) {}

private:
    T1 m_Name;
    T2 m_Age;
};

// 4. 类外实现友元函数
template<class T1, class T2>
void printPerson2(Person<T1, T2> p) {
    cout << "类外实现——姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
}

​五、核心对比总结​
​特性​​类内实现友元函数​​类外实现友元函数​
​代码耦合度​高(函数与类强绑定)低(函数与类解耦)
​复用性​差(仅限当前类使用)好(可复用为其他类的友元)
​编译依赖​无需前向声明需前向声明模板类和函数模板
​适用场景​简单逻辑、快速实现复杂逻辑、多类协作
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值