c++模板(6)--类模板

1 类模板的基本概念

类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。

类模板和函数模板区别:

  1. 类模板不可以使用自动类型推导,只能用显示指定类型
  2. 类模板中可以有默认参数

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

  1. 类模板中的成员函数 并不是一开始创建的,而是在运行阶段确定出T的数据类型才去创建
//类模板用于实现类所需数据的类型参数化
template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

void test01()
{
	//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
	Person<string, int>P1("德玛西亚", 18);
	P1.showPerson();
}

2 类模板做函数参数

  1. 指定传入类型
  2. 参数模板化
  3. 整个类模板化

通常使用方法一:指定传入类型

//类模板
template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->mName = name;
		this->mAge = age;
	}
	void PrintPerson()
	{
		cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

//1. 类模板做函数参数,指定传入类型
void doWork1(Person<string,int>& p)
{
	p.mAge += 20;
	p.mName += "_vip";
	p.PrintPerson();
}

//2. 类模板做函数参数,参数模板化
template<class T1, class T2>
void doWork2(Person<T1, T2>& p)
{
	// 查看T1、T2的数据类型
	cout << "T1的数据类型:" << typeid(T1).name() << endl;
	cout << "T2的数据类型:" << typeid(T2).name() << endl;
	p.mAge += 20;
	p.mName += "_vip";
	p.PrintPerson();
}

//3. 类模板做函数参数,整个类模板化
template<class T>
void doWork3(T &p)
{
	cout << "T的数据类型:" << typeid(T).name() << endl;
	p.mAge += 20;
	p.mName += "_vip";
	p.PrintPerson();
}

int main()
{
	Person<string, int> p("John", 30);
	doWork1(p);
	doWork2(p);
	doWork3(p);

	return 0;
}


3 类模板碰到继承的问题

3.1 类模板派生普通类

必须要指定出父类中的T数据类型,才能给子类分配内存

//类模板
template<class T>
class MyClass
{
public:
	MyClass(T property)
	{
		this->mProperty = property;
	}
public:
	T mProperty;
};

//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的
//这样c++编译器才能知道给子类分配多少内存

//普通派生类
class SubClass : public MyClass<int>
{
public:
	SubClass(int b) : MyClass<int>(20)
	{
		this->mB = b;
	}
public:
	int mB;
};

3.2 类模板派生类模板

可以指定出父类中的T数据类型,也可以再用子类模板中的一个T2数据类型代表父类模板中的T数据类型

//父类类模板
template<class T>
class Base
{
	T m;
};

// 1 指定出父类中的T数据类型
template<class T >
class Child1 : public Base<double>  //继承类模板的时候,必须要确定基类的大小
{
public:
	T mParam;
};

// 2 用子类模板中的一个T2数据类型代表父类模板中的T数据类型
template<class T1, class T2>
class Child2 : public Base<T2>
{
public:
	T mParam;
};

void test01()
{
	Child1<int> d1;

	Child2<int,double> d1;
}


4 类模板的类内类外实现

4.1 类模板的类内实现

template<class NameType, class AgeType>
class Person
{
public:
	// 类模板的类内实现
	Person(NameType name, AgeType age)
	{
		this->mName = name;
		this->mAge = age;
	}
	// 类模板的类内实现
	void showPerson()
	{
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

void test01()
{
	//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
	Person<string, int>P1("德玛西亚", 18);
	P1.showPerson();
}

4.2 类模板的类外实现

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

public:
	T1 mName;
	T2 mAge;
};

// 相比较普通的类,类外实现多了
// 1. template<class T1, class T2>
// 2. 类名后添加<T1,T2>

// 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->mName = name;
	this->mAge = age;
}


template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

void test01()
{
	//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
	Person<string, int>P1("德玛西亚", 18);
	P1.showPerson();
}


5 类模板的头文件和源文件分离问题

// Person.h文件
#pragma once

template<class T1,class T2>
class Person{
public:
	Person(T1 name,T2 age);
	void ShowPerson();
public:
	T1 mName;
	T2 mAge;
};
// Person.cpp文件
#include "Person.h"

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

template<class T1, class T2>
void Person<T1, T2>::ShowPerson()
{
	std::cout << "Name:" << this->mName << " Age:" << this->mAge << std::endl;
}
// main.cpp文件
#include <iostream>
#include "Person.h"
using namespace std;

int mian()
{
	Person<string, int> p("Obama", 20);
	p.ShowPerson();

	return 0;
}

出现问题:

  1. 在Linux如果只包含Person.h头文件,那么会报错链接错误。

问题原因:

  1. 类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。
  2. C++编译规则为独立编译。

解决方案:

  1. 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).
//解决方法  Person.hpp文件
#pragma once

template<class T1,class T2>
class Person{
public:
	// 声明
	Person(T1 name,T2 age);
	void ShowPerson();
public:
	T1 mName;
	T2 mAge;
};

// 实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->mName = name;
	this->mAge = age;
}

template<class T1, class T2>
void Person<T1, T2>::ShowPerson()
{
	std::cout << "Name:" << this->mName << " Age:" << this->mAge << std::endl;
}
// main.cpp文件
#include <iostream>
#include "Person.hpp"
using namespace std;

int mian()
{
	Person<string, int> p("Obama", 20);
	p.ShowPerson();

	return 0;
}


6 类模板碰到友元函数

6.1 友元函数类内实现

#include <iostream>
#include <cstring>
using namespace std;

template<class T1, class T2> 
class Person
{
    // 友元函数类内实现
    friend void printPerson(Person<T1,T2> &p) 
    {   
        cout << "名字: " << p.m_Name << " 年龄: " << p.m_Age << endl;
    }   
public:
    Person(T1 name, T2 age)
    {   
        this->m_Name = name;
        this->m_Age = age;
    }   

private:
    T1 m_Name;
    T2 m_Age;
};

int main()
{
    Person<string, int> p("小明", 18);

    printPerson(p);

    return 0;
}

6.2 友元函数类外实现

#include <iostream>
#include <cstring>
using namespace std;

// 告诉编译器这个类模板是存在的
template<class T1, class T2> 
class Person;

// 告诉编译器这个函数模板是存在
template<class T1,class T2> 
void printPerson(Person<T1,T2> &p);
/*
 * 或者可以将printPerson友元函数实现放在此处
{
    cout << "名字: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
*/

template<class T1, class T2> 
class Person
{
    // 友元函数类内声明,注意添加空模板列表<>, 因为友元函数是个模板函数
    friend void printPerson<>(Person<T1,T2> &p);
public:
    Person(T1 name, T2 age)
    {   
        this->m_Name = name;
        this->m_Age = age;
    }   

private:
    T1 m_Name;
    T2 m_Age;
};

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

int main()
{
    Person<string, int> p("小明", 18);

    printPerson(p);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值