c++模板类的分文件编写和友元

1.7类模板分文件编写

有两种组织方式:

                             组织方式1.直接cpp型,仍然在.h头文件中写类的定义,在.cpp文件中写类的声明,然后直接包含cpp(不包含.h,因为模板类的函数只有在调用的时候才现产生,包含.h的话代码里面虽然有函数代码,但实际上并未产生函数,在cpp中才会产生,这是和普通函数不一样的地方)

                             组织方式2.hpp型,把类的定义和类的实现写到一个文件中,然后改成hpp文件,直接包含hpp文件就行(.hpp=.h+.cpp)

下面先看

1.包含.cpp型

"lei.h"头文件中的代码,类的定义
#pragma once //在使用预编译指令#include的时候,为了防止重复引用造成二义性
#include<iostream>
using namespace std;
//父类模板类
template<class T1, class T2>
class base {
public:
	T1 t1;
	T2 t2;
	base(T1 t1, T2 t2);
	void func();
};







"lei.cpp"的类的实现
#include"lei.h"
//构造函数的实现
template<class T1, class T2>
base<T1, T2>::base(T1 t1, T2 t2) {
	cout << "i am base" << endl;
	this->t1 = t1;
	this->t2 = t2;
}

//成员函数的实现
//一定要先在前面加上一行声明模板的template<>
template<class t1, class t2>
void base<t1, t2>::func() {
	cout << "i am func" << endl;
}










主函数
#include<iostream>
#include<string>
#include"lei.cpp"
using namespace std;
int main() {
	base<int, string>b(100, "zz");
}

2.  .hpp型

由下图可见,把类的定义和声明写在一块,然后使用.hpp文件

lei.hpp文件中模板类的定义和实现
#pragma once //在使用预编译指令#include的时候,为了防止重复引用造成二义性
#include<iostream>
using namespace std;
//父类模板类
template<class T1, class T2>
class base {
public:
	T1 t1;
	T2 t2;
	base(T1 t1, T2 t2);
	void func();
};
//构造函数的实现
template<class T1, class T2>
base<T1, T2>::base(T1 t1, T2 t2) {
	cout << "i am base" << endl;
	this->t1 = t1;
	this->t2 = t2;
}

//成员函数的实现
//一定要先在前面加上一行声明模板的template<>
template<class t1, class t2>
void base<t1, t2>::func() {
	cout << "i am func" << endl;
}










主函数中对模板类的调用
#include<iostream>
#include<string>
#include"lei.hpp"  //可以看出,这里从.cpp变成了.hpp
using namespace std;
int main() {
	base<int, string>b(100, "zz");
}

 

补充知识点:

#pragma once一般由编译器提供保证:同一个文件不会被包含多次。这里所说的”同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。无法对一个头文件中的一段代码作#pragma once声明,而只能针对文件。此方式不会出现宏名碰撞引发的奇怪问题,大型项目的编译速度也因此提供了一些。缺点是如果某个头文件有多份拷贝,此方法不能保证它们不被重复包含。在C/C++中,#pragma once是一个非标准但是被广泛支持的方式。

兼容性#pragma once方式产生于#ifndef之后。#ifndef方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once方式有些编译器不支持(较老编译器不支持,如GCC 3.4版本之前不支持#pragmaonce),兼容性不够好。#ifndef可以针对一个文件中的部分代码,而#pragma once只能针对整个文件。相对而言,#ifndef更加灵活,兼容性好,#pragma once操作简单,效率高。

 

 

1.8 全局函数作为模板类的友元

学习目标:

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

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

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

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

          要是类外实现还得想办法让编译器知道这个函数的存在,还得人为调整顺序,不仅麻烦也很容易乱。

1.类内实现法


template<class T1,class T2>
class person {
public:
	T1 age;
	T2 name;
	person(T1 age, T2 name) {
		this->age = age;
		this->name = name;
	}
   //类内全局函数实现,从书写形式上看起来有点像我是我自己的朋友的意思,如果这里不写friend,那就是一个普通的类的成员函数
	friend void print_person_in(person<T1, T2>&p) {
		cout << "类内实现时:  " << p.age << "  " << p.name << endl;
	}
};


int main() {
	person<string, int>p("张瑞强", 100);
	print_person_in(p);
}

2.类外实现法(相当麻烦,不推荐,了解就好)

//因为我下面的全局函数实现的过程中还需要person,所以我还得提前声明
template<class T1, class T2>
class person;

//还必须把这个全局函数放到模板类的前面,否则就会出现链接失败的错误。相当麻烦
template<class T1, class T2>
void print_person_out(person<T1, T2>& p) {
	cout << "类外实现时: " << p.age << "  " << p.name << endl;
}
template<class T1,class T2>
class person {
public:
	T1 age;
	T2 name;
	person(T1 age, T2 name) {
		this->age = age;
		this->name = name;
	}
};


int main() {
	person<string, int>p("张瑞强", 100);
	print_person_out(p);
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ad_m1n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值