首页 > 其他分享 >类模板的常见用法

类模板的常见用法

时间:2024-04-25 22:34:09浏览次数:28  
标签:name age 常见 用法 Person template 模板 函数

class_template

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

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 test1() {
	Person<string, int>p1("regina", 23);
	p1.showPerson();
	Person<char, float>p2('i', 23.1);
	p2.showPerson();
}

image-20240421223604510

类模板做函数参数

void param(Person<string, int>& p) {
	p.mAge += 10;
	p.mName += "regina";
	p.showPerson();
}
int main() {
	Person<string, int> p("love", 20);
	param(p);
	return 0;
}

image-20240425171013806

类模板派生普通类

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;
};
class Subclass : public Person<string, int> {
public:
	Subclass(string name, int age):Person<string, int>(name,age) {
		this->mName = name;
		this->mAge = age;
	}
};

int main() {
	Subclass p("regina", 17);
	p.showPerson();
	return 0;
}

Subclass(string name, int age):Person<string, int>(name,age)这句话首先声明带参数的构造函数里面的类型。这个类型要和后面使用类模板的父类的构造函数参数类型一样。但是当你在定义一个类时,如果该类是模板类的实例化,你可以直接使用类名而不需要指定模板参数,因为编译器可以根据构造函数参数的类型来推断模板参数的类型

类模板派生类模板

派生类不仅继承了基类的成员和行为,还继承了基类的模板参数,并可以在派生类中添加额外的模板参数或覆盖基类模板参数。这样可以使得派生类在使用时更加灵活,并且可以根据需要进行定制化。

template<class MoneyType>
class Subclass : public Person<string, int> {
public:
	Subclass(string name, int age, MoneyType have_money):Person<string, int>(name,age), havemoney(have_money) { /*这里的继承就是多一个对于自己的模板的默认构造函数的声明*/
		this->mName = name;
		this->mAge = age;
	}
	void showPerson() {
		Person<string,int>::showPerson();
		cout << "have_money: " << (havemoney ? "true" : "false") << endl;
	}
private:
	MoneyType havemoney;
};
int main() {
	Subclass<bool> p("regina", 17,true);
    /*在 main 函数中只传递了一个 bool 类型的参数,因为 Subclass 类模板只接受一个模板参数 MoneyType*/
	p.showPerson();
	return 0;
}

image-20240425175021765

类模板类内实现和类外实现

类模板类内实现指的是在类模板的定义中直接实现成员函数的方法。与普通类相似,类模板也可以在类内部实现成员函数,这意味着成员函数的定义可以直接放在类模板的声明中,而不需要在类外部再单独定义。这种方式使得代码更加简洁,并且可以避免在类外部定义时重复书写模板的参数列表。


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

template<class NameType, class AgeType>这个一共声明了三次是为什么呢?

  1. 模板类声明: 在C++中,模板类的成员函数可以直接在类的定义中进行声明和实现,但也可以在类定义之外单独实现。在类定义之外实现时,必须再次使用 template<class NameType, class AgeType> 来指明这是一个模板类的成员函数。
    • 在类定义中进行声明的情况下,模板参数已经被识别,所以无需再次声明。
  2. 类定义外的实现: 如果你在模板类的定义之外实现成员函数,则需要重新指明该成员函数属于特定的模板类。这是因为C++编译器在进行模板解析时需要知道这些函数与哪个模板类相关联。

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

类模板的头文件和源文件分离是指将类模板的声明和定义分别放置在不同的文件中的做法。通常,类模板的声明(包括模板类的成员函数声明)放在头文件(通常是 .hpp.h 文件),而类模板的实现(包括成员函数的定义)则放在源文件(通常是 .cpp 文件)中。

这种分离的做法有几个好处:

  1. 模块化: 将类模板的声明和定义分开可以更好地组织代码,使得代码结构更清晰,易于维护和理解。
  2. 编译时间: 如果类模板的实现放在源文件中,在使用该类模板的地方只需要包含头文件即可,这样可以减少编译时间,因为编译器只需要编译一次模板的实现,而不是每次包含头文件时都重新编译一次。
  3. 隐藏实现细节: 将类模板的实现放在源文件中可以隐藏模板的具体实现细节,只向用户暴露接口,提高了代码的封装性和安全性。
#pragma once
/*是一种预处理器指令,用于确保在编译过程中头文件只被包含一次,以避免多重包含问题。

当编译器遇到 #pragma once 时,它会在编译过程中记住这个头文件的路径和文件名,
并在后续的 #include 指令中检查是否已经包含了相同的文件。如果已经包含过了,
那么该头文件将被忽略,不会再次包含。这样可以防止由于多重包含而导致的编译错误
或者重复定义的问题。

使用 #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() {
	cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

模板类碰到友元函数

template<class T1, class T2> class Person;
template<class T1, class T2> void PrintPerson2(Person<T1, T2>& p);

template<class T1, class T2>
class Person {
	//1. 友元函数在类内实现
	friend void PrintPerson(Person<T1, T2>& p) {
		cout << "Name:" << p.mName << " Age:" << p.mAge << endl;
	}
	//2.友元函数类外实现
	//告诉编译器这个函数模板是存在
	friend void PrintPerson2<>(Person<T1, T2>& p);//<> 是用来指示编译器,PrintPerson2 是一个函数模板的声明

	//3. 类模板碰到友元函数模板
	template<class U1, class U2>
	friend void PrintPerson(Person<U1, U2>& p);
public:
	Person(T1 name, T2 age) {
		this->mName = name;
		this->mAge = age;
	}
	void showPerson() {
		cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
	}
private:
	T1 mName;
	T2 mAge;

};
template<class T1, class T2>
void PrintPerson2(Person<T1, T2>& p)
{
	cout << "Name2:" << p.mName << " Age2:" << p.mAge << endl;
}
void test1() {
	Person<string, int> p("regina", 25);
	PrintPerson(p);
	PrintPerson2(p);
}

以下是为什么需要在类外部声明友元模板函数的原因:

  1. 预声明模板函数:当你在类内使用 friend 关键字声明一个友元模板函数时,你实际上告诉编译器这个函数会访问类的私有成员。但是这并不等同于定义了这个模板函数。因此,你仍然需要在类外部定义并实现这个模板函数。如果没有外部的声明和实现,编译器将无法找到这个函数模板,导致链接错误。
  2. 函数模板的明确声明:在使用友元模板函数时,编译器需要明确知道它是一个模板函数,并且知道它如何被实例化。如果你不在类外部声明这个函数模板,编译器可能不会正确处理其实例化,导致意外的编译错误。
  3. 类内部声明只是告诉编译器:在类内部通过 friend 声明友元模板函数只是告诉编译器该模板函数能够访问类的私有成员,并没有定义该函数的具体实现。因此,必须在类外部提供该函数模板的声明和实现,以确保编译器知道它的具体实现位置。

标签:name,age,常见,用法,Person,template,模板,函数
From: https://www.cnblogs.com/ivanlee717/p/18158767

相关文章

  • [题解]P5656 【模板】二元一次不定方程 (exgcd)
    P5656【模板】二元一次不定方程(exgcd)若存在\(ax+by=c\),则可以根据特解\(x,y\)求出任意通解\(x',y'\):\(\begin{cases}x'=x+k*\frac{b}{\gcd(a,b)}\\y'=y-k*\frac{a}{\gcd(a,b)}\end{cases}(k\in\mathbb{Z})\)求特解的方法是「扩展欧几里得(exgcd)」,如果没接触过可以先阅读......
  • wpf DataTemplate 动态模板内容
     <DataGridTemplateColumnWidth="50"Header="选择">              <DataGridTemplateColumn.CellTemplate>                <DataTemplate>                       ......
  • phpcms pc:get 标签用法;phpcms模板中使用PHP标签
     注意:变量 $catid 需要是从控制器里解析出来的<divclass="show-right-top"><divclass="sch-recruit-right-title"><p><imgsrc="/statics/boot/images/quan3.png">快速链接</p></div>......
  • Postergresql常见操作
    Postergresql常见操作1.安装部署略2.登录数据库查看版本##以管理员身份postgres登陆,然后通过#psql-Upostgres#sudo-i-upostgres​$psqlxc_hzh_linan          #登录xc_hzh_linan数据库$psql-Upostgrestest       #以......
  • 大型企业不同安全域文件交换,常见方式的优势与问题对比
    现在越来越多的企业通过对网络进行物理或逻辑隔离,将内部网络与外部网络隔离开来,从而限制非法访问和恶意渗透,防止敏感数据泄露和恶意代码的传播,提高网络安全性。对于大型企业而言,将网络分为内外网并不足以满足安全管控的需求,它们会在内部再分割不同的安全域,如黄区、绿区、红区;如生......
  • [题解]P5431 【模板】模意义下的乘法逆元 2
    可恶,卡常好难受。P5431【模板】模意义下的乘法逆元2将分数通分,第\(i\)个分数是\(\frac{k^i*fac\diva[i]}{fac}\),\(fac\)表示所有元素的积。我们可以用\(lr,rl\)记录\(a\)的前缀后缀积,第\(i\)个分数就是\(\frac{k^i*lr[i-1]*rl[i+1]}{lr[n]}\)。这样分母都是\(lr[n]\),分子就......
  • 【模板】分解质因数 Pollard-Rho
    参见洛谷模板题题解,这里只有代码实现。一些强数据参考(输出了最大质因子)79223372036854775783Prime9223371994482243049303700049392232532901085832072097143214748364822147483647Prime21471175694633721417005691289#include<bits/stdc++.h>usingnamespace......
  • 模板
    什么是模板模板是一种通用的编程工具,允许程序员编写通用的类或函数,以便在不同的数据类型上进行操作。模板可以让程序员编写一次代码,然后根据需要在编译时生成特定类型的代码实例。这种特性统称为泛型编程。voidSwap(int&a,int&b){ inttemp=a; a=b; b=temp;}v......
  • 72.Oradebug用法
    oracle之oradebug命令用法oradebug的前身是在ORACLE7时的ORADBX,它可以启动用停止跟踪任何会话,dumpSGA和其它内存结构,唤醒ORACLE进程,如SMON、PMON进程,也可以通过进程号使进程挂起和恢复等,还有很多功能,实际上这些功能都不常用,但是我们在看别人做问题诊断时,常看到别人在......
  • 常见越权方式有哪些?
    越权(UnauthorizedAccess)是指攻击者利用漏洞或不当配置,以未经授权的方式访问系统中的资源或执行操作。常见的越权方式包括:2直接访问URL:攻击者直接通过输入URL地址或修改URL参数的方式来访问系统中的受保护资源。例如,通过修改订单页面的URL参数来访问其他用户的订单信息......