template<class NameType,class AgeType = int>
class Person{
public:
Person(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson()
{
cout << "name: " << this->m_Name << " age = " << this->m_Age << endl;
}
NameType m_Name;
AgeType m_Age;
};
int main(){
//Person p("孙悟空", 1000); 错误,无法用自动类型推导
Person<string, int>p("孙悟空", 1000); //正确,只能用显示指定类型
Person<string>p1("猪八戒", 999);//默认参数
p.showPerson();
p1.showPerson();
}
3、类模板中成员函数只在调用时才会创建
//两个类
Class Person1{
void showPerson1()
};
Class Person2{
void showPerson2()
};
//类模板
template<class T>
Class MyClass{
T obj;
void func1(){
obj.showPerson1();
}
void func2(){
obj.showPerson2();
}
};
//测试
int main(){
MyClass<Person2>m;
m.func2();
}
#include<iostream>
using namespace std;
#include <string>
template<class T1,class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson()
{
cout << "姓名: " << this->m_Name << " 年龄: " << this->m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
//1、指定传入类型(这个常用)
void printPerson1(Person<string, int>&p)
{
p.showPerson();
}
void test01()
{
Person<string, int>p("孙悟空", 100);
printPerson1(p);
}
//2、参数模板化
template<class T1,class T2>
void printPerson2(Person<T1, T2>&p)
{
p.showPerson();
cout << "T1 的类型为: " << typeid(T1).name() << endl;
cout << "T2 的类型为: " << typeid(T2).name() << endl;
}
void test02()
{
Person<string, int>p("猪八戒", 90);
printPerson2(p);
}
//3、整个类模板化
template<class T>
void printPerson3( T &p)
{
p.showPerson();
cout << "T的数据类型为: " << typeid(T).name() << endl;
}
void test03()
{
Person<string, int>p("唐僧", 30);
printPerson3(p);
}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}
template<class T>
class Base
{
T m;
};
//子类声明时,指定父类T
class Son:public Base<int>
{
};
//如果想灵活指定父类中T类型,子类也需要变类模板
template<class T1,class T2>
class Son2 :public Base<T2>
{
public:
Son2()
{
cout << "T1的类型为: " << typeid(T1).name() << endl;
cout << "T2的类型为: " << typeid(T2).name() << endl;
}
T1 obj;
};
void test02()
{
Son2<int, char>S2;
}
//通过全局函数 打印Person信息
//提前让编译器知道Person类存在
template<class T1, class T2>
class Person;
//类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{
cout << "类外实现 --- 姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
template<class T1,class T2>
class Person
{
//全局函数 类内实现
friend void printPerson(Person<T1,T2> p)
{
cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}
//全局函数 类外实现
//加空模板参数列表
//如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
friend void printPerson2<>(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;
};
//1、全局函数在类内实现
void test01()
{
Person<string, int>p("Tom", 20);
printPerson(p);
}
//2、全局函数在类外实现
void test02()
{
Person<string, int>p("Jerry", 20);
printPerson2(p);
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
类模板成员函数在调用阶段创建,导致分文件编写链接不到
1、直接包含.cpp文件
#include "Complex.cpp"
int main(){}
//函数实现放在类中
//Complex.cpp
#include<iostream>
using namespace std;
template <typename T>
class Complex
{
friend Complex Mysub(Complex &c1, Complex &c2)
{
Complex temp(c1.a - c2.a, c1.b - c2.b);
return temp;
}
//friend ostream& operator<<(ostream &out, Complex &c3);//函数体外实现
friend ostream& operator<<(ostream &out, Complex &c3)
{
out << "a:" << c3.a << " b:" << c3.b << endl;
return out;
}
public:
Complex(T a, T b )
{
this->a = a;
this->b = b;
}
//重载运算符
Complex operator+(Complex &c2)
{
Complex temp(a + c2.a, b + c2.b);
return temp;
}
void printCom()
{
cout << "a:" << a << "b" << b << endl;
}
protected:
private:
T a;
T b;
};
//ostream& operator<<(ostream &out, Complex &c3)
//{
// out << "a:" << c3.a << " b:" << c3.b << endl;
// return out;
//}
2、将声明和实现放在同一个文件中,并更改后缀名为.hpp
//complex.h
#include<iostream>
using namespace std;
template <typename T>
class Complex
{
//有元函数是全局函数,不属于这个类的
friend Complex Mysub(Complex &c1, Complex &c2);
//不加<T>报错LINK2019,两次编译每次生成的函数头不一样
friend ostream& operator<< <T>(ostream &out, Complex &c3); //重载<<
public:
Complex(T a, T b);//构造
void printCom();
Complex operator+(Complex &c2);//重载+
/*Complex operator-(Complex &c2);*/
private:
T a;
T b;
};
//complex.hpp
#include<iostream>
using namespace std;
#include "complex.h"
//构造函数写在类的外部..h和.cpp
template<typename T>
Complex<T>::Complex(T a, T b)
{
this->a = a;
this->b = b;
}
template<typename T>
void Complex<T>::printCom() //函数的名前加类的域名,因为他是成员函数
{
cout << "a:" << a << "b" << b << endl;
}
//成员函数,实现+运算符重载
template<typename T>
Complex<T> Complex<T>::operator+(Complex<T> &c2) //第一个是Complex<T>函数的返回值,参数也要具体化,名称也加域名;函数体内部要不要具体化无所谓
{
Complex temp(a + c2.a, b + c2.b);
return temp;
}
//友元函数实现<<重载
template<typename T>
ostream& operator<<(ostream &out, Complex<T>&c3) //全局函数,不属于类,不加域名
{
out << "a:" << c3.a << " b:" << c3.b << endl;
return out;
}
//友元函数实现-重载
template<typename T>
Complex<T> Mysub(Complex<T> &c1, Complex<T> &c2)
{
Complex temp(c1.a - c2.a, c1.b - c2.b);
return temp;
}
//测试代码
//#include "complex.h"
//#include "complex.cpp"//这里一点要注意了,要不然找不到函数体,两次编译惹的祸,所有常将cpp命名为hpp.与.h文件合二为一
#include "complex.hpp"
int main()
{ //需要将模板类具体化后,才能定义对象,C++编译器要分配内存
Complex<int> c1(1, 2);
Complex<int> c2(3, 4);
Complex<int> c3 = c1 + c2;
cout << c3 << endl;
//滥用友元
Complex <int> c4=Mysub(c1,c2);
cout << c4 << endl;
cout<<"hello..."<<endl;
system("pause");
return 0;
}
//MyVector.h
#include<iostream>
using namespace std;
template<typename T>
class MyVector
{
friend ostream & operator<< <T>(ostream &out, const MyVector &obj);
public:
MyVector(int size = 0);
MyVector(const MyVector &obj);//拷贝构造函数
~MyVector();
public:
T& operator[](int index);//中括号重载
MyVector& operator=(const MyVector &obj);
public:
int getlen()
{
return m_len;
}
protected:
private:
T *m_space;
int m_len;
};
//MyVector.cpp
#include<iostream>
using namespace std;
#include "MyVector.h"
template<typename T>
ostream & operator<<(ostream &out, const MyVector<T> &obj)
{
for (int i = 0; i < obj.m_len; i++)
{
out << obj.m_space[i]<<" ";
}
cout << endl;//换行
return out;
}
//MyVector<int> myv1(10);构造函数
template<typename T>
MyVector<T>::MyVector(int size)
{
m_space = new T[size];
m_len = size;
}
//MyVector<int> myv2 = myv1;
template<typename T>
MyVector<T>::MyVector(const MyVector &obj)//拷贝构造函数根据myv1大小分配内存,cpy数据
{
m_len = obj.m_len;
m_space = obj.m_space;
for (int i = 0; i < obj.m_len; i++)
{
m_space[i] = obj.m_space[i];
}
}
template<typename T>
MyVector<T>::~MyVector()
{
if (m_space != NULL)
{
delete[]m_space;
m_space = NULL;//避免野指针
m_len;
}
}
template<typename T>
T& MyVector<T>::operator[](int index)//中括号重载
{
return m_space[index];
}
//a3=a2=a1
template<typename T>
MyVector<T>& MyVector<T>::operator=(const MyVector<T> &obj)
{
//先把a2的旧的内存释放掉
if (m_space != NULL)
{
delete[]m_space;
m_space = NULL;//避免野指针
m_len;
}
//根据a1分配内存
m_len = obj.m_len;
m_space = new T[m_len];
//copy数据
for (int i = 0; i < m_len;i++)
{
m_space[i] = obj.m_space[i];
}
return *this;//返回数组的引用,即a2;
}
//MyVector 测试代码
#include<iostream>
using namespace std;
#include "MyVector.cpp"
//#define _CRT_SECURE_NO_WARNINGS
class Teacher //1优化Teacher类,属性变成char *pname,构造函数里分配内存 2.析构函数释放pname指向的内存空间 3.避免浅拷贝,重载= ,重写拷贝函数 4,在teacher增加<<
{
public: //在模板数组类,存int char,Teacher, Teacher*;
Teacher()
{
age = 33;
//strcpy(name, "");
m_p = new char[1];
strcpy(m_p, "");
}
Teacher(char *name, int age)
{
this->age = age;
//strcpy(this->name, name);
m_p = new char[strlen(name) + 1];
strcpy(m_p, name);
}
Teacher(const Teacher &obj)
{
m_p = new char[strlen(obj.m_p) + 1];
strcpy(m_p, obj.m_p);
age = obj.age;
}
~Teacher()
{
if (m_p!=NULL)
{
delete[]m_p;
m_p = NULL;
}
}
void prinT()
{
//cout << name << "," << age << endl;
cout << m_p << "," << age << endl;
}
public:
friend ostream & operator<<(ostream &out, Teacher &t);
Teacher& operator=(const Teacher & obj)
{
if (m_p!=NULL)
{
delete[]m_p;
m_p = NULL;
age = 33;
}
m_p = new char[strlen(obj.m_p) + 1];
age = obj.age;
strcpy(m_p, obj.m_p);
return *this;
}
private:
int age;
//char name[32];
char *m_p; //深拷贝,和浅拷贝
};
ostream & operator<<(ostream &out, Teacher &t)
{
out << t.m_p << "," << t.age << endl;
return out;
}
void main()//存指针
{
Teacher t1("Li", 30), t2("YU", 24), t3("Zhao", 21);
MyVector<Teacher*>tArry(3);
tArry[0] = &t1; //t1丢进容器里面
tArry[1] = &t2;
tArry[2] = &t3;
for (int i = 0; i < 3; i++)
{
Teacher *tmp = tArry[i];
tmp->prinT();
}
//cout << tArry;//类对象没有实现左移,所以不能调用底层的<<重载
system("pause");
}
void main7()
{
MyVector<char> myv1(10);
myv1[0] = 'a';
myv1[1] = 'b';
cout << myv1;
system("pause");
}
int main6()
{
MyVector<int> myv1(10);
for (int i = 0; i < myv1.getlen(); i++)
{
myv1[i] = i + 1;
cout << myv1[i] << " ";
}
cout << endl;
MyVector<int> myv2 = myv1;
for (int i = 0; i < myv2.getlen(); i++)
{
cout << myv2[i] << " ";
}
cout << endl;
cout << myv2 << endl;//重载操作符
//operator<<(ostream &out,const MyVector &obj)
cout << "hello..." << endl;
system("pause");
return 0;
}
//自己的通用的数组类
//MyArray.hpp
#pragma once
#include <iostream>
using namespace std;
template<class T>
class MyArray
{
public:
//有参构造 参数 容量
MyArray(int capacity)
{
//cout << "Myarray有参构造调用" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//拷贝构造
MyArray(const MyArray& arr)
{
//cout << "Myarray拷贝构造调用" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//this->pAddress = arr.pAddress;//浅拷贝(编译器)导致堆区的数据重复释放
//深拷贝(在堆区重新开辟一个空间)
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止浅拷贝问题 (a=b=c,=返回引用实现连续赋值)
MyArray& operator=(const MyArray& arr)
{
//cout << "Myarray 的 operator=调用" << endl;
//先判断原来堆区是否有数据,如果有先释放
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷贝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[arr.m_Capacity];
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
//尾插法
void Push_Back(const T & val)
{
//判断容量是否等于大小
if (this->m_Capacity == this->m_Size)
{
return;
}
this->pAddress[this->m_Size] = val; //在数组末尾插入数据
this->m_Size++; //更新数组大小
}
//尾删法
void Pop_Back()
{
//让用户访问不到最后一个元素,即为尾删,逻辑删除
if (this->m_Size == 0)
{
return;
}
this->m_Size--;
}
//通过下标方式访问数组中的元素 arr[0] = 100
T& operator[](int index)
{
return this->pAddress[index];
}
//返回数组容量
int getCapacity()
{
return this->m_Capacity;
}
//返回数组大小
int getSize()
{
return this->m_Size;
}
//析构函数
~MyArray()
{
if (this->pAddress != NULL)
{
//cout << "Myarray析构函数调用" << endl;
delete[] this->pAddress;
this->pAddress = NULL;
}
}
private:
T * pAddress; //指针指向堆区开辟的真实数组
int m_Capacity; //数组容量
int m_Size; //数组大小
};
#include<iostream>
using namespace std;
#include "MyArray.hpp"
#include <string>
void printIntArray(MyArray <int>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << endl;
}
}
void test01()
{
MyArray <int>arr1(5);
for (int i = 0; i < 5; i++)
{
//利用尾插法向数组中插入数据
arr1.Push_Back(i);
}
cout << "arr1的打印输出为: " << endl;
printIntArray(arr1);
cout << "arr1的容量为: " << arr1.getCapacity() << endl;
cout << "arr1的大小为: " << arr1.getSize() << endl;
MyArray <int>arr2(arr1);//拷贝构造,深拷贝
cout << "arr2的打印输出为: " << endl;
printIntArray(arr2);
//尾删
arr2.Pop_Back();
cout << "arr2尾删后:" << endl;
cout << "arr2的容量为: " << arr2.getCapacity() << endl;
cout << "arr2的大小为: " << arr2.getSize() << endl;
//MyArray <int>arr3(100);
//arr3 = arr1;//清空原来的100,再赋值
}
//测试自定义数据类型
class Person
{
public:
Person() {};
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void printPerosnArray(MyArray<Person>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名: " << arr[i].m_Name << " 年龄: " << arr[i].m_Age << endl;
}
}
void test02()
{
MyArray<Person> arr(10);
Person p1("孙悟空", 999);
Person p2("韩信", 30);
Person p3("妲己", 20);
Person p4("赵云", 25);
Person p5("安其拉", 27);
//将数据插入到数组中
arr.Push_Back(p1);
arr.Push_Back(p2);
arr.Push_Back(p3);
arr.Push_Back(p4);
arr.Push_Back(p5);
//打印数组
printPerosnArray(arr);
//输出容量
cout << "arr容量为: " << arr.getCapacity() << endl;
//输出大小
cout << "arr大小为: " << arr.getSize() << endl;
}
int main() {
//test01();
test02();
system("pause");
return 0;
}