首页 > 编程语言 >c++学习笔记——模板和IO(一)

c++学习笔记——模板和IO(一)

时间:2023-02-19 22:11:07浏览次数:33  
标签:name age c++ void IO Maker 模板 cout

前言

本文主要作为本人学习C\C++历程的的一种记录,以期望通过这种方式加深对知识点的记忆,查漏补缺。如有写得不对的地方,欢迎大家批评改正。

模板概论

模板是泛型编程的基础,是创建泛型类或函数的蓝图或公式。
C++提供了两种模板机制:函数模板和类模板。函数模板,实际上是建立了一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。类模板和函数模板的定义和使用类似。
下面开始逐一介绍C++模板的应用。

函数模板

定义函数模板

点击查看代码
template<class T>	//注意:T代表泛型的数据类型,不是只能写T,
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

也可以这样定义函数模板

点击查看代码
template<typename T>
void mySwap(T& a,T& b)
{

}

怎么使用函数模板?

点击查看代码
template<class T>	//注意:T代表泛型的数据类型,不是只能写T,
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}
void test01()
{
	int a = 10;
	int b = 20;
	mySwap(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

//可以这样定义函数模板
//template<typename T>
//void func(T a, T b)
//{
//
//}

template<class T>
T func1(T a, T b)
{
	return a + b;
}
void test02()
{
	int a = 10;
	double b = 20.3;
	//如果使用参数列表指定数据类型,那么实参中可以隐式转换,
	//如果转换成功,就调用,转换不成功就报错
	cout << func1<int>(a, b) << endl;
}

普通函数和函数模板的区别

点击查看代码
//1.普通函数可以进行隐式转换,函数模版不能直接的进行隐性转换

//普通函数
int myPlus(int a, int b)
{
	cout << "普通函数" << endl;
	return a + b;
}

//函数模板
template<class T>
int myPlus(T a, T b)
{
	cout << "函数模板" << endl;
	return a + b;
}

void test01()
{
	int a = 10;
	double b = 20;
	myPlus(a, b);	//普通函数可以进行隐性转换
	//myPlus2(a, b);	//没有与参数列表匹配的 函数模板 "myPlus2" 实例	
	myPlus<int>(a, b);	//如果要进行隐性转换,必须加上参数列表
}

普通函数和函数模板的调用规则

点击查看代码
//普通函数
int myPlus(int a, int b)
{
	cout << "普通函数" << endl;
	return a + b;
}

//函数模板
template<class T>
int myPlus(T a, T b)
{
	cout << "函数模板" << endl;
	return a + b;
}
//函数模板重载
template<class T>
void myPlus(T a, T b, T c)
{
	cout << "函数模板myPlus(T a, T b, T c)" << endl;
}
//1、函数模板和普通函数都可以重载
void test02()
{
	int a = 10;
	int b = 20;
	//2、如果普通函数和函数模板都可以实现的功能,普通函数优先调用
	myPlus(a, b);
	
	//3、可以使用<>空参数列表强制调用函数模板
	myPlus<>(a, b);

	//4、函数模板之间也可以进行重载

	//5、如果函数模板可以产生更好的匹配,那么优先使用函数模板
	char c1 = 'a';
	char c2 = 'b';
	myPlus(c1, c2);
}

模板机制剖析——c++编译器是如何实现函数模板机制的?

  1. 编译器并不是把函数模板处理成能够处理任何类型的函数
  2. 函数模板通过具体类型产生不同的函数
  3. 编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

模板也具有局限性

点击查看代码
template<class T>
void mycompare(T a, T b)
{
	if (a > b)
	{
		cout << "a>b" << endl;
	}
	else
	{
		cout << "a<=b" << endl;
	}
}

void test01()
{
	//如果传入的是数组名,那么函数模板中比较函数名的大小就没有意义
	int arr[20];
	int arr2[10];

	mycompare(arr, arr2);
}

为解决上述问题,提出了两种方法

第一种:使用函数模板具体化

点击查看代码
class Maker
{
public:
	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
public:
	string name;
	int age;
};

template<class T>
void myfunc(T& a, T& b)
{
	if (a > b)
	{
		cout << "a>b" << endl;
	}
	else
	{
		cout << "a<=b" << endl;
	}
}
//具体化函数模板,注意上面的函数模板要有,才能具体化
template<>void myfunc<Maker>(Maker& a, Maker& b)
{
	cout << "函数模板的具体化" << endl;
	if (a.age > b.age)
	{
		cout << "a>b" << endl;
	}
	else
	{
		cout << "a<=b" << endl;
	}
}

第二种:重载操作符

点击查看代码
class Maker1
{
public:
	Maker1(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
public:
	string name;
	int age;
};

bool operator>(Maker1& m1, Maker1& m2)
{
	if (m1.name > m2.name && m1.age > m2.age)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test()
{
	Maker1 a("aaa", 18);
	Maker1 b("bbb", 20);
	if (a > b)
	{
		cout << "a>b" << endl;
	}
	else
	{
		cout << "a<=b" << endl;
	}
}

定义类模板

点击查看代码
//类模板是把类中的数据类型参数化
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}
	void printMaker()
	{
		cout << "Name:" << this->name << "Age:" << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

类模板的使用

点击查看代码
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}
	void printMaker()
	{
		cout << "Name:" << this->name << "Age:" << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

//类模板的使用
void test()
{
	//1.类模版不会自动推导数据类型,要显示的告诉编译器是什么类型
	Maker<string, int> m("高启强", 35);
	m.printMaker();

	//2.注意传入的参数,传入参数类型要程序员自己把握
	Maker<int, int>m2(18, 20);
	m2.printMaker();

	//Maker<>m3("aaa", 18);	//err:类模板“Maker"的参数太少,必须通过参数列表告诉编译器是什么类型

}

类模板和函数模板的区别

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

类模板的默认类型及其使用

点击查看代码
template<class NameType, class AgeType=int>
class Maker2
{
public:
	Maker2(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMaker()
	{
		cout << "Name:" << this->name << "Age:" << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

void test02()
{
	//如果有默认类型,那么<>里可以少写类型
	Maker2<string> m("高启强", 35);
	//Maker2<string, int> m("高启兰", 20);
	m.printMaker();
	//以传入的类型为准
	Maker2<string, double> m2("高启盛", 24.22);
	m2.printMaker();
}

//5、类模板的默认参数注意
//默认类型后面的泛型类型都必须有默认类型
template<class NameType, class AgeType = int, class T = int>
class Maker3
{
public:
	Maker3(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMaker()
	{
		cout << "Name:" << this->name << " Age:" << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

void test03()
{
	Maker3<string> m("高启强", 35);
	m.printMaker();
}

类模板做函数参数

点击查看代码
template<class NameType, class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}
	void printMaker()
	{
		cout << "name = " << this->name << " " << " age = " << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

//类模板做函数参数
	//1.指定传入的数据类型
void func(Maker<string, int>& m)
{
	m.printMaker();
}


	//2.参数模版化(常用)
template<class T1, class T2>
void func2(Maker<T1, T2>& m)
{
	m.printMaker();
}

	//3.整个类 模版化
template<class T>
void func3(T& m)
{
	m.printMaker();
}

类模板的继承

点击查看代码
//1、普通类继承类模板
template<class T>
class Father
{
public:
	Father()
	{
		m = 20;
	}
public:
	T m;
};

//普通类 继承 类模板
class Son : public Father<int>	//2、要告诉编译器父类的泛型数据类型具体是什么类型
{
public:

};

//2、类模板 继承 类模板
//类模板 继承 类模板
template<class T1,class T2>
class Son2 :public Father<T2>	//要告诉编译器父类的泛型数据类型具体是什么类型
{

};

类模板的成员函数的类内实现

点击查看代码
template<class NameType,class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void printMaker()
	{
		cout << "Name:" << this->name << " " << "Age:" << this->age << endl;
	}
public:
	NameType name;
	AgeType age;
};

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

点击查看代码
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 << "Name:" << this->name << " " << "Age:" << this->age << endl;
}

类模板的友元实现

类内实现

点击查看代码
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;

};

类外实现

点击查看代码
//1、声明模板
template<class NameType,class AgeType>
class Maker2;
//2、声明函数模板
//告诉编译器下面有printMaker2的实现
template<class NameType,class AgeType>
void printMaker2(Maker2<NameType, AgeType>& p);

template<class NameType, class AgeType>
class Maker2
{
	//3、在函数名和()之间加上<>
	friend void printMaker2<>(Maker2<NameType, AgeType>& p);
	//编译器不知道printMaker2下面有没有实现,需要知道函数的结构
public:
	Maker2(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}
private:
	NameType name;
	AgeType age;
};
//友元在类外实现要写成函数模板
template<class NameType,class AgeType>
void printMaker2(Maker2<NameType, AgeType>& p)
{
	cout << "类外实现的友元函数" << " "<<p.name << " " << p.age << endl;
}

类模板实现数组

MyArray.hpp

点击查看代码
#pragma once

template<class T>
class MyArray
{
public:
	MyArray(int capacity)
	{
		this->mCapacity = capacity;
		this->mSize = 0;
		//T如果是Maker,这里要调用什么构造函数,要调用无参构造
		p = new T[this->mCapacity];
	}
	//拷贝构造
	MyArray(const MyArray &arr)
	{
		this->mCapacity = arr.mCapacity;
		this->mSize = arr.mSize;
		p = new T[arr.mCapacity];

		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];
		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;
		}
		cout << "析构函数" << endl;
	}

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

private:
	T* p;
	int mCapacity;
	int mSize;
};
类模板实现数组.cpp
点击查看代码
#define _CRT_SECURE_NO_WARNINGS
#include<string>
#include<iostream>
using namespace std;
#include"MyArray.hpp"
class Maker
{
public:
	Maker() 
	{
		cout << "无参构造" << endl;
	}
	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()
{
	//Maker类型
	MyArray<Maker>myarr(4);
	Maker m1("小明", 18);
	Maker m2("小强", 19);
	Maker m3("小栋", 20);
	Maker m4("小兴", 21);
	myarr.Push_Back(m1);
	myarr.Push_Back(m2);
	myarr.Push_Back(m3);
	myarr.Push_Back(m4);
	printMaker(myarr);

	//int类型
	MyArray<int>myint(10);
	for (int i = 0; i < 10; i++)
	{
		myint.Push_Back(i + 1);
	}
	for (int i = 0; i < 10; i++)
	{
		cout << myint[i] << " " << endl;
	}
}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

总结

模板是一个比较重要的概念,是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
-学习C++任重而道远,本人愚钝,唯有勤加练习方能查漏补缺。

标签:name,age,c++,void,IO,Maker,模板,cout
From: https://www.cnblogs.com/cloudseastore/p/17135769.html

相关文章

  • ChatGPT国内镜像模板,国内使用ChatGPT中文版本
    @目录一、什么是ChatGPT国内镜像二、ChatGPT国内镜像使用教程免费ChatGPT镜像的功能:三、ChatGPT中文版作用四、怎么使用ChatGPT国内镜像五、中文ChatGPT镜像站介绍一、什......
  • Linux、Rust、C++学习笔记(day1)
    序言从今天开始以Ubuntu22.04为开发环境,学习Linux、Rust和C++的开发。博文作为个人学习记录和分享,欢迎各位与笔者讨论交流!开发环境搭建我的机器是腾讯云的云服务器。腾......
  • IO流详解
    简介IO是Input和Output的简称,即输入和输出,数据读取到计算机内存中的过程就是输入,内存中的数据输出到外部(如文件和数据库)的过程就是输出。IO流在Java中分为输入流和输出......
  • Spring-IOC、AOP、事务的说明
    今天来聊一聊我对spring框架的认识,本篇章中不详细讲解具体的使用方法和实现一、spring是什么?spring是一个java语言下的bean管理的基础框架。二、spring的常用功能有那......
  • Educational DP Contest - J - Sushi
    定义\(dp[i][j][k]\)是初始情况为:总共有n个盘子,其中\(i\)个盛有1个寿司的盘子,\(j\)个盛有2个寿司的盘子,\(k\)个盛有3个寿司的盘子,在这种初始情况下将寿司全部吃完的期望......
  • Educational Codeforces Round 143 (Rated for Div. 2) C(二分+差分维护)
    EducationalCodeforcesRound143(RatedforDiv.2)C(二分+差分维护)C.TeaTasting题目大意:给定n杯茶,n个人,一个进行n论赏茶,赏茶的规律如下:第1轮,第一个人喝第1杯茶,......
  • 异常01-Error和Exception
    什么是异常实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你......
  • 关于数据库事务隔离级别(Transaction)
    问题背景:最近在学习Spring的事务部分,其中涉及到了Spring事务属性的配置,其中一个isolation把我整懵逼了isolation设置事务的隔离级别DEFAULT:默认隔离级别,会采用......
  • 期权定价之希腊值推导(Derivation of Greeks in European Option Pricing)
    DerivationofGreeksinEuropeanOptionPricingTheEuropeanVanillacallandputoptionswithdividendpaymentshavethevaluesinformulaswith:\[\begin{al......
  • 第八章 IO库
    第八章IO库前面章节已经在用的IO库设施istream:输入流类型,提供输入操作。ostream:输出流类型,提供输出操作cin:一个istream对象,从标准输入读取数据。cout:一个ostream对......