• C++模板(类模板)


    类模板

    • 类模板作用:建立一个通用类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表。

    • 语法:
      template < typename T>

    • 解释:
      template-----声明创建模板。
      typename-----表明其后面的符号是一种数据类型,可以用class代替。
      T-----通用的数据类型,名称可以替换,通常为大写字母。

    • 类模板与函数模板的区别主要有两点:
      1、类模板没有没有自动类型推导的使用方式,只能用显示指定类型
      2、类模板在模板参数列表中可以有默认参数

      示例:

    #include 
    #include 
    using namespace std;
    template <class name_type,class age_type = int>//区别2指定为int类型,函数模板没有
    class Person
    {
    public:
    	Person(string name, int age)
    	{
    		this->m_name = name;
    		this->m_age = age;
    	}
    	void Show()
    	{
    		cout << "name:" << this->m_name << " age: " << this->m_age << endl;
    	}
    	name_type m_name;
    	age_type m_age;
    };
    void test01()
    {
    //	Person<> p1("张三", 18);区别1
    	Person<string,int> p1("张三",18);//必须使用显示指定类型的方式,使用类模板
    	p1.Show();
    }
    void test02()
    {
    	Person<string> p2("李四", 20);//区别2,类模板中的模板参数列表,可以指定默认参数
    	p2.Show();
    }
    int main(void)
    {
    	test01();
    	test02();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    总结:类模板和函数模板非常相似,在声明模板template后面加类,此类称为类模板。


    类模板中成员函数创建时机

    • 类模板中成员函数和普通类中成员函数创建时机是有区别的:
      1、普通类中的成员函数一开始就可以创建。
      2、类模板中的成员函数在调用时才创建。
    #include 
    #include 
    using namespace std;
    class Person1
    {
    public:
    	void show1()
    	{
    		cout << "Person1类中成员函数的调用" << endl;
    	}
    };
    class Person2
    {
    public:
    	void show2()
    	{
    		cout << "Person2类中成员函数的调用" << endl;
    	}
    };
    template <class T>
    class Myclass
    {
    public:
    	T obj;
    	//类模板中的成员函数并不是一开始就创建的,而是在模板调用时再生成
    	void func1() {obj.show1(); }
    	void func2() {obj.show2(); }
    };
    void test01()
    {
    	Myclass<Person1>m;
    	m.func1();
    //	m.func2();//编译会出错,说明函数调用时才会去创建成员函数
    }
    
    int main(void)
    {
    	test01();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建。


    类模板对象做函数参数

    • 一共有三种传入方式:
      1、指定传入的类型-----直接显示对象的数据类型(常用)
      2、参数模板化-----将对象中的参数变为模板进行传递
      3、整个类模板化-----将这个对象类型模板化进行传递
      补充知识点:
      如何查看变量或对象的数据类型

    • 语法typeid(变量或对象).name()

    include <iostream>
    #include 
    using namespace std;
    template <class type_name,class type_age>
    class Person
    {
    public:
    	Person(type_name name, type_age age)
    	{
    		this->m_name = name;
    		this->m_age = age;
    	}
    	void showprint()
    	{
    		cout << "name: " << this->m_name << " age: " << this->m_age << endl;
    	}
    	type_name m_name;
    	type_age m_age;
    };
    void printPerson1(Person<string,int>&p)//指定传入的类型
    {
    	p.showprint();
    }
    
    template <class T1,class T2>//参数模板化
    void printPerson2(Person<T1, T2>& p)
    {
    	p.showprint();
    	cout << "T1的数据类型为: " << typeid(T1).name() << endl;//查看T1的数据类型
    	cout << "T2的数据类型为: " << typeid(T2).name() << endl;
    }
    
    template <class T>//整个类模板化
    void printPerson3(T & p3)
    {
    	cout << "T的类型为: " << typeid(T).name() << endl;//查看T的数据类型
    	p3.showPerson();
    }
    void test01()
    {
    	Person <string, int>p1("张三", 18);
    	printPerson1(p1);
    
    	Person <string, int>p2("李四",19);
    	printPerson2(p2);
    
    	Person <string, int>p3("王五",20);
    	printPerson2(p3);
    }
    
    int main(void)
    {
    	test01();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    总结:
    1、通过类模板创建的对象,可以有三种方式向函数中进行传参。
    2、使用比较广泛是第一种:指定传入的类型。


    类模板与继承

    • 注意事项
      1、当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型。如果不指定,编译器无法给子类分配内存。
      2、如果想灵活指出父类中T的类型,子类也需变为类模板。
    include <iostream>
    #include 
    using namespace std;
    template <class T>
    class Base
    {
    public:
    	Base() {
    		cout << "T的数据类型为: " << typeid(T).name() << endl;//int
    	}
    };
    //class son : public Base//事项1:必须要指定出父类T的数据类型
    class son1 : public Base<int>{};
    
    template <class T1,class T2>//事项2:想灵活指出父类中T的类型,子类也需变为类模板
    class son2 : public Base<T1>
    {
    public:
    	son2(){
    		cout << "T1的数据类型为: " << typeid(T1).name() << endl;//int
    		cout << "T2的数据类型为: " << typeid(T2).name() << endl;//char
    	}
    };
    void test()
    {
    	son1 p1;
    	son2<int, char>p2;
    }
    int main(void)
    {
    	test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    总结如果父类是类模板,子类需要指定出父类中T的数据类型。


    类模板成员函数类外实现

    • 类模板中成员函数类外实现时,需要加上模板参数列表
    #include 
    #include 
    using namespace std;
    template <class T1,class T2>
    class Person
    {
    public:
    	Person(T1 name,T2 age);//类内构造函数的声明
    	void func();//类内成员函数的声明
    	string m_name;
    	int m_age;
    };
    //构造函数类外实现
    template <class T1, class T2>
    Person<T1,T2>::Person(T1 name,T2 age)
    {
    	this->m_age = age;
    	this->m_name = name;
    	cout << "Person类构造函数的调用" << endl;
    }
    //成员函数类外实现
    template <class T1, class T2>
    void Person<T1, T2>::func()
    {
    	cout << "姓名: " << this->m_name << endl;
    	cout << "年龄: " << this->m_age << endl;
    }
    void test()
    {
    	Person<string,int>p1("Tom", 18);
    	p1.func();
    }
    int main(void)
    {
    	test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    类模板分文件编写

    • 问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到。
    • 解决:
      解决方式1:直接包含.cpp源文件。
      解决方法2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制的。
    //#include "person.h"
    #include "person.cpp"//方式1
    #include "person.hpp"//方式2
    void test()
    {
    	Person<string,int>p1("Tom", 18);
    	p1.func();
    }
    int main(void)
    {
    	test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    方式2:将声明和实现写在一个文件.hpp中。

    #include 
    #include 
    using namespace std;
    template <class T1, class T2>
    class Person
    {
    public:
    	Person(T1 name, T2 age);//类内构造函数的声明
    	void func();//类内成员函数的声明
    	T1 m_name;
    	T2 m_age;
    };
    //以下为实现部分(或将以下部分写在另一个.cpp文件中,并只包含.cpp文件即可)
    //构造函数类外实现
    template <class T1, class T2>
    Person<T1, T2>::Person(T1 name, T2 age)
    {
    	this->m_age = age;
    	this->m_name = name;
    	cout << "Person类构造函数的调用" << endl;
    }
    //成员函数类外实现
    template <class T1, class T2>
    void Person<T1, T2>::func()
    {
    	cout << "姓名: " << this->m_name << endl;
    	cout << "年龄: " << this->m_age << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    总结推荐的解决方式是第二种,将类模板函数写在一起,并将后缀名改为.hpp。


    类模板与友元

    • 如果全局函数类内实现-----直接在类内声明友元即可(推荐)。
    • 如果全局函数类外实现-----需要提前让编译器知道全局函数的存在。
    #include 
    #include 
    using namespace std;
    
    template <class T1, class T2>
    class Person;//用到person这个数据类型,要提前声明
    
    template <class T1, class T2>
    void showprint2(Person<T1, T2>& p)//函数定义要写在类前面,提前让编译器知道
    {
    	cout << "姓名为: " << p.m_name << endl;
    	cout << "年龄为: " << p.m_age << endl;
    }
    
    
    template <class T1,class T2>
    class Person
    {
    	friend void showprint2<>(Person<T1, T2>& p);
    
    	friend void showprint1(Person<T1, T2>& p) {//全局函数配合友元类内实现
    		cout << "姓名为: " << p.m_name << endl;
    		cout << "年龄为: " << p.m_age << endl;
    	}
    public:
    	Person(T1 age, T2 name) {
    		this->m_age = age;
    		this->m_name = name;
    	}
    private:
    	T1 m_age;
    	T2 m_name;
    }; 
    
    
    void test()
    {
    	Person<string, int>p1("Tom", 18);
    	showprint1(p1);
    
    	Person<string, int>p2("Jerry", 16);
    	showprint1(p2);
    }
    int main(void)
    {
    	test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别。

  • 相关阅读:
    springboot+maven大学校友活动风采展示管理信息系统
    网络安全(黑客)自学
    SSM项目源码基于ssm的NBA球队|篮球管理系统
    NSS [NISACTF 2022]middlerce
    Elasticsearch 浅尝
    用Python爬取短视频列表
    如何利用 Flutter 实现炫酷的 3D 卡片和帅气的 360° 展示效果
    计算空间物体包围球的两种算法实现
    『Linux项目自动化构建工具』make/Makefile
    iOS开发之Swift画三角形
  • 原文地址:https://blog.csdn.net/weixin_62142545/article/details/126457418