zoukankan      html  css  js  c++  java
  • 学习:类模板

    类模板的使用:

    类模板作用:

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

    在自己看来是给自己创建的类来使用的模板

    语法:

    template<typename T>

    解释:

    template --- 声明创建模板

    typename --- 表面其后面的符号是一种数据类型,可以用class代替

    T --- 通用的数据类型,名称可以替换,通常为大写字母

    示例代码

    #include<iostream>
    #include<string>
    using namespace std;
    
    template<class NameType, class AgeType>  //定义一个类模板
    class Person {
    public:
    	Person(NameType name, AgeType age) {
    		this->age = age;
    		this->name = name;
    	}
    
    	void showinfo() {
    		cout << this->age << endl;
    		cout << this->name << endl;
    	}
    public:
    	NameType name;
    	AgeType age;
    };
    
    void test01() {
    	Person<string, int>p1("adexx", 18);
    	p1.showinfo();
    
    }
    
    
    int main() {
    	test01();
    	system("pause");
    	return 0;
    
    }
    

    类模板和函数模板的区别:

    1、类模板不会自动推导的使用方式,也就是调用的时候需要自己指定类型
    2、类模板在模板参数列表中可以有默认参数,下面的代码中会有体现

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    template<class NameType, class AgeType = int>  //定义一个类模板,我们还可以对传参进行指定默认参数
    class Person {
    public:
    	Person(NameType name, AgeType age) {  
    		this->age = age;
    		this->name = name;
    	}
    
    	void showinfo() {
    		cout << this->age << endl;
    		cout << this->name << endl;
    	}
    public:
    	NameType name;
    	AgeType age;
    };
    
    int main() {
    	//Person p1("adexx", 18); //直接生成不行,需要指定类型
    	//Person<string, int>p1("adexx", 18); //可以
    	Person<string>p1("adecc", 19);//对上面指定了默认参数 只需要指定一个类型string就可以
    	system("pause");
    	return 0;
    }
    

    总结:

    1、类模板使用只能用显示指定类型方式
    2、类模板中的模板参数列表可以有默认参数


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

    类模板中成员函数和普通类中成员函数创建时机是有区别的:

    1、普通类中的成员函数一开始就可以创建
    2、类模板中的成员函数在调用时才创建

    示例代码:

    #include<iostream>
    #include<string>
    using namespace std;
    
    class Person1
    {
    public:
    	void showPerson1()
    	{
    		cout << "Person1 show" << endl;
    	}
    };
    
    class Person2
    {
    public:
    	void showPerson2()
    	{
    		cout << "Person2 show" << endl;
    	}
    };
    
    template<class T>
    class Myclass {
    public:
    
    	T obj;
    	void func1() {
    		obj.showPerson1();
    	}
    
    	void func2() {
    		obj.showPerson2();
    	}
    };
    
    
    int main() {
    	Myclass<Person1> m;
    	m.func1();
    	//m.func2();  两条一起执行就会报错, 但是注释掉一条就不会报错,所以说明了类模板中的函数调用的时候只有调用的时候才创建,要不然不创建
    	system("pause");
    	return 0;
    
    }
    

    类模板与继承:

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

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

    示例代码:

    #include<iostream>
    #include<string>
    using namespace std;
    
    template<class T>
    class A {
    public:
    
    	T age;
    };
    
    //class B :public A {  无法直接继承父类模板 需要指定参数才行
    //
    //};
    
    
    class C:public A<int> { //第一点的体现,这样的是可以生成的 ,但是也有个缺点,这样子的话父类只能是我们设定的类型,在这里的话 就只能是int类型了,那有什么办法能更灵活点呢
    
    };
    
    
    template<class T1,class T2>
    class B :public A<T2>{ // 第三点的体现
    public:
    	B(T1 name) {
    		this->name = name;
    		cout << this->name << endl;
    		cout << typeid(T1).name() << endl;
    		cout << typeid(T2).name() << endl;
    	}
    public:
    	T1 name;
    };
    
    
    int main() {
    	B<string, int>b1("adexx"); // B指定的参数 string为类模板的T1,int为子类中的T2也就是父类的T-age
    	system("pause");
    	return 0;
    
    }
    

    类模板成员函数类外实现:

    示例代码:

    #include<iostream>
    #include<string>
    using namespace std;
    
    
    //类模板成员函数的类外实现
    
    
    //定义一个类模板Person
    template<class AgeT,class NameT>
    class Person {
    public:
    	//进行函数申明
    	Person(AgeT age,NameT name);
    	void showinfo();
    
    public:
    	AgeT m_age;
    	NameT m_name;
    };
    
    //类外成员函数实现
    
    template<class AgeT,class NameT>
    Person<AgeT,NameT>::Person(AgeT age,NameT name) { //类外进行定义构造函数
    	this->m_age = age;
    	this->m_name = name;
    }
    
    template<class AgeT,class NameT>
    void Person<AgeT, NameT>::showinfo() { // 类外进行定义成员函数
    	cout << this->m_age << " " << this->m_name << endl;
    }
    
    int main() {
    	Person<int,string>p1(18, "adexx");
    	p1.showinfo();
    	system("pause");
    	return 0;
    
    }
    

    总结:类模板中成员函数类外实现时,需要加上模板参数列表,例如上面的就是加上<AgeT, NameT>


    类模板的分文件编写:

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

    解决:

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

    学到这里其实自己也还是不太懂为什么要这样搞,主要链接的原理不太懂,学到后面自己再慢慢进行理解嗯吧

    示例代码:
    person.hpp

    #pragma once
    #include<iostream>
    #include<string>
    
    using namespace std;
    
    template<class t1, class t2>
    class Person {
    
    public:
    	Person(t1 name, t2 age);
    	void showInfo();
    
    public:
    	t1 m_name;
    	t2 m_age;
    };
    
    template<class t1, class t2>
    Person< t1, t2>::Person(t1 name, t2 age) {
    	this->m_name = name;
    	this->m_age = age;
    }
    
    
    template<class t1, class t2>
    void Person< t1, t2>::showInfo() {
    	cout << this->m_age << endl;
    	cout << this->m_name << endl;
    }
    

    源.cpp

    #include "person.hpp"
    
    //template<class t1,class t2>
    //class Person {
    //
    //public:
    //	Person(t1 name,t2 age);
    //	void showInfo();
    //
    //public:
    //	t1 m_name;
    //	t2 m_age;
    //};
    //
    //template<class t1,class t2>
    //Person< t1, t2>::Person(t1 name, t2 age) {
    //	this->m_name = name;
    //	this->m_age = age;
    //}
    //
    //
    //template<class t1,class t2>
    //void Person< t1,  t2>::showInfo() {
    //	cout << this->m_age << endl;
    //	cout << this->m_name << endl;
    //}
    
    
    
    
    int main() {
    	Person<string, int> p1("zpchcbd", 18);
    	p1.showInfo();
    	system("pause");
    	return 0;
    
    }
    

    类模板与友元:

    全局函数类内实现:直接在类内声明友元即可

    全局函数类外实现:需要提前让编译器知道全局函数的存在

    示例代码:

    #include<iostream>
    #include<string>
    using namespace std;
    
    template<class t1, class t2>class Person; //全局函数配合友元  类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元
    
    template<class t1, class t2>
    void showInfo2(Person<t1, t2> & p1)  //因为类中已经进行friend声明,所以而可以直接进行定义了
    {
    	cout << "类外实现---- 姓名: " << p1.m_name << " 年龄:" << p1.m_age << endl;
    }
    
    template<class t1,class t2>
    class Person {
    public:
    
    	Person(t1 m_age,t2 m_name) { //构造函数
    		this->m_age = m_age;
    		this->m_name = m_name;
    	
    	}
    
    	friend void showInfo2<>(Person<t1, t2> & p1); //全局函数类外实现
    
    	friend void showInfo(Person<t1,t2> & p1) {  //全局函数类内实现,这里头一次学习到friend来声明类内函数,类外可以直接进行调用 参考文章https://www.jianshu.com/p/2dffb88b0fe5
    		cout << p1.m_age << endl;
    		cout << p1.m_name << endl;
    	}
    private:
    	t1 m_age;
    	t2 m_name;
    };
    
    void test01() { //全局函数类内实现
    	Person<int, string>p1(18, "adexx");
    	showInfo(p1);
    }
    
    void test02() { //全局函数类外实现
    	Person<int, string>p1(18, "adexx");
    	showInfo2(p1);
    }
    
    int main() {
    	//test01(); 全局函数类内实现调用
    	test02(); //全局函数类外实现调用
    	system("pause");
    	return 0;
    }
    
  • 相关阅读:
    在 Docker 搭建 Maven 私有库
    Maven:mirror和repository 区别
    ubuntu DEBIAN_FRONTEND环境变量用法
    Redis常见面试题
    Error:(1, 1) java: 非法字符: ‘ufeff’
    jpa 查询方法和sql查询语句对应关系
    net.sf.json.JSONObject对时间戳的格式化处理
    美团Leaf——全局序列生成器
    Logstash
    Kafka和SpringBoot
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/11914196.html
Copyright © 2011-2022 走看看