C++类模板学习笔记

一、概述

  • 类模板的定义
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

public:
	NameType name;
	AgeType age;
};

int main()
{

	return EXIT_SUCCESS;
}

  • 类模板的使用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 类模板  不固定类成员变量的参数类型
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMaker()
	{
		cout << this->name << " " << this->age << endl;
	}

public:
	NameType name;
	AgeType age;
};

void test()
{
	// 类模板不会自动推导数据类型  需要显示的告诉编译器是什么类型
	Maker<string, int> m("悟空", 18);
	m.printMaker();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

  • 类模板和函数模板的区别
    类模板不会自动推导数据类型,要显示的告诉编译器是什么类型,但是函数模板可以根据实参来推导数据类型

传入的参数类型 需要程序员自己去把握
template<class NameType,class AgeType>

// 通过指定参数类型 然后传入参数
	Maker<string, int> m("悟空", 18);
	m.printMaker();

	Maker<int, int> n(11,11);
	n.printMaker();
  • 类模板的默认参数

可以给类模板指定参数类型

这里给类模板指定参数类型int template

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 类模板  不固定类成员变量的参数类型
// 这里给出了默认类型int 但是创建对象时 可以具体指定参数列表类型
template<class NameType = int,class AgeType = int>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMaker()
	{
		cout << this->name << " " << this->age << endl;
	}

public:
	NameType name;
	AgeType age;
};

void test()
{
	// 类模板不会自动推导数据类型  需要显示的告诉编译器是什么类型
	Maker<string, int> m("悟空", 18);
	m.printMaker();

	Maker<int, int> n(11,11);
	n.printMaker();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}
  • 类模板的默认参数注意

默认类型后面的泛型类型都必须有默认类型

二、复数的模板类

  • 目的:对象c1(3,4),对象c2(3,9),对象c3 = c1.Maker_add(c2),c3的两个成员变量会等于a + 3 + 5,
    b = 4 + (-10), 并且数据类型可以不同

  • 通过成员函数实现 返回类

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 设置默认参数类型为int
template<class T = int>
class Maker
{
public:
	// 默认构造参数
	Maker()
	{
		a = 0;
		b = 0;
	}

	// 有参构造函数
	Maker(T r,T i)
	{
		a = r;
		b = i;
	}

	Maker Maker_add(Maker& c2)
	{
		Maker<T> c;// 设置临时变量  
		c.a = this->a + c2.a;
		c.b = this->b + c2.b;
		return c;
	}

	void printMaker()
	{
		cout << "a = " << a << ", " << "b = " << b;
	}

private:
	T a;
	T b;
};

void test()
{
	// 设置参数列表Int类型
	Maker<int> c1(3, -4);
	Maker<int> c2(5, -10);
	Maker<int> c3;// 使用默认构造函数

	c3 = c1.Maker_add(c2);
	c3.printMaker();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 设置默认参数类型为int
template<class T = int>
class Maker
{
public:
	// 默认构造参数
	Maker()
	{
		a = 0;
		b = 0;
	}

	// 有参构造函数
	Maker(T r,T i)
	{
		a = r;
		b = i;
	}

	Maker Maker_add(Maker& c2)
	{
		Maker<T> c;// 设置临时变量  
		c.a = this->a + c2.a;
		c.b = this->b + c2.b;
		return c;
	}

	void printMaker()
	{
		cout << "a = " << a << ", " << "b = " << b;
		cout << endl;
	}

private:
	T a;
	T b;
};

void test()
{
	// 设置参数列表Int类型
	Maker<int> c1(3, -4);
	Maker<int> c2(5, -10);
	Maker<int> c3;// 使用默认构造函数

	c3 = c1.Maker_add(c2);
	c3.printMaker();

	Maker<double> d1(3.0, -4.1);
	Maker<double> d2(5.1, -10.1);
	Maker<double> d3;// 使用默认构造函数

	d3 = d1.Maker_add(d2);
	d3.printMaker();

}

int main()
{
	test();
	return EXIT_SUCCESS;
}

  • 通过重载运算符进行实现
	// 重载加号运算符
	Maker operator+(Maker& c2)
	{
		// 创建临时对象 进行有参构造
		Maker tmp(this->a + c2.a,this->b + c2.b);
		return tmp;
	}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 设置默认参数类型为int
template<class T = int>
class Maker
{
public:
	// 默认构造参数
	Maker()
	{
		a = 0;
		b = 0;
	}

	// 有参构造函数
	Maker(T r,T i)
	{
		a = r;
		b = i;
	}

	Maker Maker_add(Maker& c2)
	{
		Maker<T> c;// 设置临时变量  
		c.a = this->a + c2.a;
		c.b = this->b + c2.b;
		return c;
	}

	// 重载加号运算符
	Maker operator+(Maker& c2)
	{
		// 创建临时对象 进行有参构造
		Maker tmp(this->a + c2.a,this->b + c2.b);
		return tmp;
	}

	void printMaker()
	{
		cout << "a = " << a << ", " << "b = " << b;
		cout << endl;
	}

private:
	T a;
	T b;
};

void test()
{
	// 设置参数列表Int类型
	Maker<int> c1(3, -4);
	Maker<int> c2(5, -10);
	Maker<int> c3;// 使用默认构造函数

	c3 = c1 + c2;
	c3.printMaker();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

三、类模板作为函数参数


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 设置类模板的参数  默认参数是int
template<class TypeName = int,class TypeAge = int>
class Maker
{
public:
	Maker(TypeName a, TypeAge b)
	{
		this->name = a;
		this->age = b;
	}
	void PrintMaker()
	{
		cout << this->name << " " << this->age << endl;
	}

public:
	TypeName name;
	TypeAge age;
};


// 类模板作为函数参数
void func(Maker<string, int>& m)
{
	m.PrintMaker();
}

// 或者直接参数模板化
template<class T1,class T2>
void func2(Maker<T1, T2>& m)
{
	m.PrintMaker();
}

void test()
{
	Maker<string, int> m1("ddd",21);
	func(m1);

	func2(m1);
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

四、类模板的继承

类模板的继承:需要告诉编译器父类的泛型数据具体是什么样的数据类型

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 设置类模板
template<class T = int>
class Father
{
public:
	Father()
	{
		m = 20;
	}

public:
	T m;
};

// 普通类  继承模板类的时候需要具体指定参数类型 这里参数列表设置为int
// 要告诉编译器 父类的泛型数据具体是什么类型的数据
class Son :public Father<int>
{
public:

};

template<class T1, class T2>
// 这里要告诉编译器父类的泛型数据类型具体是什么类型的数据  这里指定T2类型
class Son2 :public Father<T2>
{

};

void test()
{
	Son2<int, int> s;// 这里指定T2 是string 类型 说明父类的成员变量的类型是string 
	cout << s.m << endl;
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

五、类模板的成员函数类内和类外实现

5.1 成员函数类内实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 成员函数类内实现
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMkaer()
	{
		cout << this->name << " " << this->age << " " << endl;
	}

public:
	NameType name;
	AgeType age;
};

int main()
{
	test();
	return EXIT_SUCCESS;
}

5.2 类模板的成员函数的类外实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

// 成员函数类内实现
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age);
	void printMaker();

public:
	NameType name;
	AgeType age;
};

// 类模板的成员函数类外实现
// 要写成函数模板的形式
template<class NameType,class AgeType>
// 需要指定具体的参数类型  然后再使用作用域符号
Maker<NameType,AgeType>::Maker(NameType name, AgeType age)
{
	cout << "构造函数" << endl;

	this->name = name;
	this->age = age;
}

template<class NameType,class AgeType>
void Maker<NameType, AgeType>::printMaker()
{
	cout << this->name <<" "<<this->age << endl;
}

void test()
{
	Maker<string, int> m("hhh", 11);
	m.printMaker();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

六、类模板分文件编写问题和解决办法

  • 调用类模板的时候,需要进行二次编译,要把泛型的数据类型替换为具体的类型,这时候需要知道函数体,但是函数的实现是在.cpp中,那么调用类模板的.cpp没有引入实现.cpp 之引入.h 所以报错

  • 解决办法:将成员函数放到.h中,然后将.h改为.hpp 然后在调用成员函数的地方 引入.hpp

  • 为什么.hpp中有成员的实现,然后再调用类模板的地方引入.hpp,不会报重定义。类的成员函数默认申请为内联函数,在连接的时候,链接器会对重复的成员函数进行处理,只保留一份成员函数,所以不会进行报错

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
#include"Maker.hpp"

int main()
{
	Maker<string, int> m("悟空",22);
	m.printMaker();

	return EXIT_SUCCESS;
}

Maker.hpp

// 防止多次编译
#pragma once
#include<iostream>
using namespace std;

template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name,AgeType age);
	void printMaker();

public:
	NameType name;
	AgeType age;
};


// 实现类模板中的成员函数 需要使用函数模板进行引入
template<class NameType, class AgeType>
Maker<NameType, AgeType>::Maker(NameType name, AgeType age)
{
	cout << "构造函数" << endl;
	this->name = name;
	this->age = age;
}

template<class NameType, class AgeType>
void Maker<NameType, AgeType>::printMaker()
{
	cout << this->name << " " << this->age << " " << endl;
}

七、类模板和友元

  • 友元函数类内实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

template<class NameType,class AgeType>

class Maker
{
	friend void printMaker(Maker<NameType, AgeType>& p)
	{
		cout << "类内实现" << p.name << " " << p.age << endl;
	}

public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

private:
	NameType name;
	AgeType age;
};

void test1()
{
	Maker<string, int> m("悟空",11);
	printMaker(m);
}

int main()
{
	
	test1();
	return EXIT_SUCCESS;
}

  • 友元函数类外实现

使用函数模板的方式进行实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

template<class NameType, class AgeType>
class Maker;
template<class NameType,class AgeType>
void printMaker(Maker<NameType, AgeType>& p);

template<class NameType, class AgeType>
class Maker
{
	friend void printMaker<>(Maker<NameType, AgeType>& p);
	

public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

private:
	NameType name;
	AgeType age;
};

void test1()
{
	Maker<string, int> m("悟空",11);
	printMaker(m);
}

template<class NameType,class AgeType>
void printMaker(Maker<NameType, AgeType>& p)
{
	cout << "类外实现的友元函数" << p.name << " " << p.age << endl;
}

void test2()
{
	Maker<string, int> m("悟空",19);
	printMaker(m);
}

int main()
{
	
	test1();
	return EXIT_SUCCESS;
}

七、类模板实现数组

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
#include"MyArray.hpp"
#include<string>

class Maker
{
public:

	Maker() {}

	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}

public:
	string name;
	int age;
};

void printMaker(MyArray<Maker>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名" << arr[i].name << "年龄" << arr[i].age << endl;
	}
}

void test()
{
	MyArray<Maker> myarr(4);
	Maker m1("悟空",11);
	Maker m2("悟空1",11111);
	Maker m3("悟空2",1111);
	Maker m4("悟空3",111);
	myarr.Push_Back(m1);
	myarr.Push_Back(m2);
	myarr.Push_Back(m3);
	myarr.Push_Back(m4);

}

int main()
{
	test();
	return EXIT_SUCCESS;
}

MyArray.hpp

#pragma once
template<class T>

class MyArray {
public:
	MyArray(int capacity)
	{
		this->mCapacity = capacity;
		this->mSize = 0;
		p = new T[this->mCapacity];// 创建数组空间
	}

	// 拷贝构造
	MyArray(const MyArray& arr)
	{
		this->mCapacity = arr.mCapacity;
		this->mSize = arr.mSize;
		p = new T[arr.mCapacity];// 开辟一个和arr 相同大小的数组

		// 然后开始复制数值
		for (int i = 0; i < this->mSize; i++)
		{
			p[i] = arr.p[i];
		}
	}

	// 赋值函数  重载赋值运算符
	MyArray& operator = (const MyArray& arr)
	{
		if (this->p != NULL)
		{
			delete[] this->p;
			this > p = NULL;
		}

		p = new T[arr.mCapacity];// 创建一个T类型的数组  数组长度就是arr的长度
		this->mSize = arr.mSize;
		this->mCapacity = arr.mCapacity;
		for (int i = 0; i < this->mSize; i++)
		{
			p[i] = arr.p[i];
		}

		return *this;
	}

	// 重载[]
	T& operator[](int index)
	{
		return this->p[index];
	}

	// 尾插
	void Push_Back(const T &val)
	{
		if (this->mSize == this->mCapacity)
		{
			return;
		}

		this->p[this->mSize] = val;
		this->mSize++;
	}

	// 尾删
	void Pop_back()
	{
		if (this->mSize == 0)
		{
			return;
		}

		this->mSize--;
	}

	// 析构函数
	~MyArray()
	{
		if (this->p != NULL)
		{
			delete[] p;
			p = NULL;
		}
	}

	int getSize()
	{
		return this->mSize;
	}

private:
	T* p;
	int mCapacity;
	int mSize;
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少写代码少看论文多多睡觉

求打赏,求关注,求点赞

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

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

打赏作者

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

抵扣说明:

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

余额充值