C++08

Day08总结

01函数模板的基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
*      template<typename T>告诉编译器T是万能数据类型,下面紧跟者的函数或者类中的T类型,不要报错
* 实现通过交换两个数据函数
* 调用模板函数
* 自动类型推到——必须让编译器推导出一致的T类型才可以使用模板
* 显示指定类型——显示告诉编译器T的类型mySwap<int>()
template <typename T>//T是通用类型,告诉编译器不要报错
void mySwap(T &a,T& b)
{
T temp = a;
a=b;
b=temp;
}
template <typename T>
void mySwap2()
{

}
void test01()
{
int a = 10;
int b = 20;
char x = 'x';
//1.自动类型推导,必须让编译器推导出一致的T
// swap(a,x)是不行的,如果x是char类型的
mySwap(a,b);
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
double c = 1.1;
double d = 3.1415;
mySwap(c,d);
cout<<"c="<<c<<endl;
cout<<"d="<<d<<endl;

//2. 显式指定的类型
// mySwap<int>(a,x);//x是char类型,在引用条件下是会报错的
// 显式指定类型,可以进行隐式类型转换,如果转换不成功,那么也不可以用模板
cout<<"a="<<a<<endl;
cout<<"x="<<x<<endl;
//模板函数 必须要指定出T的类型,才可以使用
mySwap2<double >();

}

02函数模板实现int和char的数组排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
template <class T>
void mySwap(T &a, T &b) {
T temp;
temp = a;
a = b;
b = temp;
}
template <class T>
void printArray(T arr[],int len)
{
for(int i = 0;i<len;i++)
{
cout<<arr[i]<<endl;
}
}
template <typename T>
void mySort(T arr[] , int len)
{
int i;
for (i = 0;i<len ;i++)
{
int min = i;
for(int j=i+1;j<len;j++)
{
if(arr[min]>arr[j])
{
min = j;//记录最小值的下表
}
}
if(min != i)
{
mySwap(arr[i],arr[min]);

}
}
}
void test01()
{
int arr[]={12,3345,31,2424,657};
int len = sizeof(arr)/sizeof(int);
mySort<int>(arr,len);
printArray<int>(arr,len);
char charArr[]="heelllooowoooorllld";
len = sizeof(charArr)/sizeof(char);
mySort<char>(charArr,len);
printArray<char >(charArr,len);

}

03普通函数和函数模板的区别以及调用规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
*      1.C++如果普通函数和函数模板可以同时调用,优先使用的是普通函数
* 2.如果想强制调用函数模板的内容可以使用空参数列表
* 3.函数模板也可以函数重载
* 4.如果函数模板可以产生更好的匹配,那么优先使用函数模板
int myPlus(int a,int b)
{
return a+b;
}
template <class T>
T myPlus2(T a,T b)
{
return a+b;
}
void test01()
{
int a = 10;
int b = 20;
char c ='c';
cout<<myPlus(a,c)<<endl;
cout<<myPlus2<int>(a,c)<<endl;
}
//普通函数和函数模板的调用规则
template <class T>
void myPrint(T a,T b)
{
cout<<"函数模板的调用"<<endl;
}
template <class T>
void myPrint(T a,T b ,T c)
{
cout<<"函数模板(重载)的调用"<<endl;
}
void myPrint(int a,int b)
{
cout<<"普通函数的调用"<<endl;
}
void test02()
{
int a = 0;
int b = 2;
int c = 0;
myPrint(a,b);
myPrint<>(a,b);//空参数列表
//3. 函数模板也可以函数重载
myPrint<>(a,b, c);
//4 如果函数模板可以产生更好的匹配,那么优先使用函数模板
char d='d';
char e = 'e';
myPrint(d,e);
//上面会调用函数模板,因为普通函数还要做隐式类型转换
}

04模板的局限性的解决—具体化

模板的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
*      用具体化技术来解决问题
* template <>
* bool myCompare<Person>(Person&a,Person&b)
* 如果是具体化和重载运算符同时出现,优先调用具体化函数
class Person{
public:
Person(string name,int age)
{
this->m_Name = name;
this->m_Age = age;
}
//下面一段用的是重载运算符来解决问题
bool operator==(Person &a)
{
cout<<"调用的是重载==运算符的代码"<<endl;
if(this->m_Name==a.m_Name&&this->m_Age==a.m_Age)
return true;
return false;
}


string m_Name;
int m_Age;

};
//通过模板将那些两个数据的 比较
template <class T>
bool myCompare(T &a,T &b)
{
if(a==b)
return true;
return false;
}
//利用函数重载或者具体化Person函数,告诉编译器走Person对比代码
template <>
bool myCompare<Person>(Person&a,Person&b)
{
cout<<"调用的是具体化的代码"<<endl;
if(a.m_Name==b.m_Name&&a.m_Age==b.m_Age)
return true;
return false;
}

void test01()
{
Person p1("SB",18);
Person p2("SB",58);
cout<<myCompare(p1,p2)<<endl;
}

05类模板和函数模板的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
*      类模板使用时候不可以用自动类型推导,必须显示指定类型
* 类模板中的类型 可以偶默认参数
* 泛型编程——体现在模板技术——特点:将类型参数化
template <class NAMETYPE,class AGETYPE=int>
class Person
{
public:
Person(NAMETYPE name,AGETYPE age)
{
this->m_Age=age;
this->m_Name=name;
}
NAMETYPE m_Name;
AGETYPE m_Age;
};
void test01()
{
// Person p1("Tom",11);这样写是错的 ,不能用自动类型推导
Person<string>p1("Tom",11);//类模板必须指定显示函数类型,上面AGETYPE已经有默认参数了,这里可以省略
cout<<"NAME IS "<<p1.m_Name<<" And AGE IS "<<p1.m_Age;
}

06类模板中成员函数创建时机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Person1
{
public:
void showPerson1()
{
cout<<"Person1 Show"<<endl;
}

};
class Person2
{
public:
void showPerson()
{
cout<<"Person2 Show"<<endl;
}
};
//类模板中的成员函数,并不是一开始就创建出来的,而是在运行阶段才创建出来
template <class T>
class myClass
{
public:
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}

T obj;
};
void test01()
{
myClass<Person1>p1;
p1.func1();
// p1.func2();
}

类模板作为函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
*      3种方式
* 1 .指定传入类型,比较常用,清楚明了
* 2. 参数模板化
* 3. 整个类模板化
template <class NAMETYPE,class AGETYPE>
class Person
{
public:
Person(NAMETYPE name,AGETYPE age)
{
this->m_Age=age;
this->m_Name=name;
}
NAMETYPE m_Name;
AGETYPE m_Age;
};
//1 .指定传入类型,比较常用,清楚明了!!!
void doWork1(Person<string,int>&p1)
{
cout<<p1.m_Age<<" AND "<<p1.m_Name<<endl;
}

void test01()
{
Person<string,int>p1("aaa",10);
doWork1(p1);
}
//2. 参数模板化
template <class T1,class T2>
void doWork2(Person<T1,T2>&person)
{
cout<<person.m_Age<<" AND "<<person.m_Name<<endl;

}
void test02()
{
//string 替换到T1上面,int 替换到T2上面
Person<string,int>p2("BBB",10);
doWork1(p2);
}
//3. 整个类模板化
template <class T>
void doWork3(T&person)
{
cout<<person.m_Age<<" AND "<<person.m_Name<<endl;
}
void test03()
{
Person<string,int>p3("CCC",10);
doWork3(p3);
}

08 类模板碰到继承问题以及解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*      如果父类是一个类模板,子类在做继承的时候,必须制定出父类中T的类型,否则无法欸父类中的T分配内存
* 语法:
* template <class T1,class T2>
class Son:public Base<T2>
template <class T>
class Base
{

};
//因为创建子类的时候会调用父类的构造函数
//所以在赋初值的时候要知道T的类型才能分配内存
//需要在Base 后加一个参数列表
template <class T1,class T2>
class Son:public Base<T2>
{
T1 m_B;
};
void test01()
{
Son<int ,double >son;
//int 是让Son初始化的
//double是让父类Base初始化的

}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
*      template<class T1 ,class T2>
* void Person<T1,T2>::showPerson()
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;
};
//以下是类外实现
template <class T1,class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template <class T1,class T2>
void Person<T1,T2>::showPerson() {
cout<<"姓名:"<<this->m_Name<<" 年龄:"<<this->m_Age<<endl;
}

void test01()
{
Person<string ,int>p("Aaaa",1002);
p.showPerson();
}

10类模板分文件编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
*       类模板不建议做份文件编写,因为要包含.cpp文件
解决方法:把类模板的声明和实现放在.hpp文件中,再在.cpp文件中包含.hpp文件,这是约定俗称的
//以下代码在.cpp中
template <class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age);
void showPerson();

T1 m_Name;
T2 m_Age;
};
template <class T1,class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
template <class T1,class T2>
void Person<T1,T2>::showPerson() {
cout<<"姓名:"<<this->m_Name<<" 年龄:"<<this->m_Age<<endl;
}

11类模板案例——数组类封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
*      属性
* T *pAddress;
* int m_Capacity;
* int m_Size;
* 行为
* 有参构造
* 拷贝构造
* 析构
* operator=
* operator[]
* 尾插法
* 尾删法
* 获取数组大小
class MyArray
{
public:
explicit /*防止隐式转换*/MyArray(int capacity)//MyArray arr(100)
{
this->m_Capacity =capacity;
this->m_Size =0;
this->pAddress = new T[this->m_Capacity];

}
//拷贝构造
MyArray(const MyArray&array)
{
this->m_Capacity=array.m_Capacity;
this->m_Size = array.m_Size;
this->pAddress = new T[this->m_Capacity];
for(int i = 0;i<m_Size;i++)
{
this->pAddress[i] = array .pAddress[i];
}

}
//有了深拷贝,需要重载复制如算符 arr1 = arr2 =arr3
MyArray&operator=(const MyArray&array)
{
//先判断原来是否有数据,如果有先释放掉
if(this->pAddress !=NULL)
{
delete[]this->pAddress;
this->pAddress = NULL;
}
this->m_Capacity=array.m_Capacity;
this->m_Size = array.m_Size;
this->pAddress = new T[this->m_Capacity];
for(int i = 0;i<m_Size;i++)
{
this->pAddress[i] = array .pAddress[i];
}
return *this;
}
//[]运算符重载 MyArray arr[0]=0;
T& operator[](int index)
{
return this->pAddress[index];
}
//尾插法********************************************/
void pushBack(const T&val)
{
//如果超出容量,就不插入
if(this->m_Capacity ==this->m_Size)
{
return;
}
this->pAddress[this->m_Size]=val;
this->m_Size++;
}
//尾删法***********************************************/
void popBack()
{
if(this->m_Size==0)
{
return;
}
this->m_Size--;
}
//返回数组大小*******************************************/
int getSize()
{
return this->m_Size;
}
//析构函数**********************************************/
~MyArray()
{
if(this->pAddress !=NULL)
{
delete[]this->pAddress;
this->pAddress = NULL;
}
}
private:
//真是开辟到堆区数据的指针
T *pAddress;
//数组容量
int m_Capacity;
//数组长度
int m_Size;
};
/*******************************************************************/
class Person{
public:
Person(){};
Person(string name,int age):m_Name(name),m_Age(age){}
string m_Name;
int m_Age;
};
void printArray(MyArray<int>(&array))
{
for (int i = 0; i < array.getSize(); i++)
{
cout<<array[i]<<" "<<endl;
}
}
void test01() {
//测试int类型数组
MyArray<int> myIntArray(100);
for (int i = 0; i < 10; i++)
{
myIntArray.pushBack(i+19);
}
//print Int类型数组
printArray(myIntArray);

}
/***********************************************/
//测试自定义类型Person
void printPerson(MyArray<Person>&myArray)
{
for(int i = 0;i<myArray.getSize();i++)
{
cout<<" NAME IS "<<myArray[i].m_Name<<" AGE IS "<<myArray[i].m_Age<<endl;
}
}
void test02()
{
MyArray<Person>personArray(10);//这样会报错,需要在class里面写默认构造函数Person(){};
Person p1("孙悟空",100);
Person p2("孙悟空2",10670);
Person p3("孙悟空3",120);
Person p4("孙悟空4",1030);
Person p5("孙悟空5",10220);
Person p6("孙悟空6",100);
Person p7("孙悟空7",1030);
Person p8("孙悟空8",102);
personArray.pushBack(p1);
personArray.pushBack(p2);
personArray.pushBack(p3);
personArray.pushBack(p4);
personArray.pushBack(p5);
personArray.pushBack(p6);
personArray.pushBack(p7);
personArray.pushBack(p8);
printPerson(personArray);
cout<<"SIZE IS "<<personArray.getSize()<<endl;
}
-------------本文结束,感谢您的阅读-------------