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;
};