C++远征之模板篇
将会学到的内容:
- 模板函数 & 模板类 -> 标准模板类
- 友元函数 & 友元类
- 静态数据成员 & 静态成员函数
- 运算符重载: 一切皆有可能
友元函数
函数定义分类:
1. 全局函数
2. 成员函数
友元全局函数
例子:
class Coordinate
{
friend void printXY(Coordinate &c);
public:
Coordinate(int x,int y);
private:
int m_iX;
int m_iY;
}
关键字friend + 声明友元函数(对象的引用或指针)
- 传入引用或指针访问速度更快,不提倡直接传入对象。
友元全局函数
2-2-FriendFunctionGlobal
Time.h
#ifndef TIME_H
#define TIME_H
#include <iostream>
using namespace std;
class Time
{
friend void printTime(Time &t);//重点
public:
Time(int hour,int min,int sec);
private:
int m_iHour;
int m_iMinute;
int m_iSecond;
};
#endif
Time.cpp
#include "Time.h"
Time::Time(int hour, int min, int sec)
{
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
}
main.cpp
#include <iostream>
#include <stdlib.h>
#include "Time.h"
using namespace std;
void printTime(Time &t);
int main()
{
Time t(6, 34, 35);
printTime(t);
system("pause");
return 0;
}
void printTime(Time &t)
{
cout << t.m_iHour << endl;
// Time::m_iHour”: 无法访问 private 成员(在“Time”类中声明)
cout << t.m_iMinute << endl;
cout << t.m_iSecond << endl;
}
要求
2-5-FriendClass
Time.h
#ifndef TIME_H
#define TIME_H
class Match;//
class Time
{
friend Match;// 声明自己友元
public:
Time(int hour,int min,int sec);
private:
void printTime();
int m_iHour;
int m_iMinute;
int m_iSecond;
};
#endif
Time.cpp
#include "Time.h"
#include <iostream>
using namespace std;
Time::Time(int hour, int min, int sec)
{
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
}
void Time::printTime()
{
cout << m_iHour << "时" << m_iMinute << "分" << "秒" << endl;
}
Match.h
#ifndef MATCH_H
#define MATCH_H
#include "Time.h"
class Match
{
public:
Match(int hour,int min,int sec);
void testTime();
private:
Time m_tTimer; // 声明朋友存在
};
#endif
Match.cpp
#include "Match.h"
#include <iostream>
using namespace std;
Match::Match(int hour, int min, int sec):m_tTimer(hour, min, sec)
{
}
void Match::testTime()
{
m_tTimer.printTime();
cout << m_tTimer.m_iHour << ":" << m_tTimer.m_iMinute << ":" << m_tTimer.m_iSecond << endl;
}
main.cpp
#include <iostream>
#include <stdlib.h>
#include "Time.h"
#include "Match.h"
using namespace std;
int main()
{
Match m(6, 30, 50);
m.testTime();
system("pause");
return 0;
}
要求
3-2-StaticMemberFunction
Tank.h
#ifndef TANK_H
#define TANK_H
class Tank
{
public:
Tank(char code);
~Tank();
void fire();
static int getCount();
private:
static int s_iCount;
char m_cCode;
};
#endif
Tank.cpp
#include <iostream>
#include "Tank.h"
using namespace std;
int Tank::s_iCount = 10; //构造函数之外,单独初始化
Tank::Tank(char code)
{
m_cCode = code;
s_iCount++;
cout << "tank" << endl;
}
Tank::~Tank()
{
s_iCount--;
cout << "~Tank()" << endl;
}
void Tank::fire()
{
cout << "Tank--fire" << endl;
}
int Tank::getCount()
//声明时添加static,定义时与普通一致
{
return s_iCount;
}
main.cpp
#include "Tank.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
cout << Tank::getCount() << endl;
//在类实例化之前就能使用
Tank t1('A');
cout << Tank::getCount() << endl;
//初值10变成11
cout << t1.getCount() << endl;
// 堆上实例化自己管理内存
Tank *p = new Tank('B');
cout << Tank::getCount() << endl;
Tank *q = new Tank('C');
cout << q->getCount() << endl;
delete p;
delete q;
cout << Tank::getCount() << endl;
system("pause");
return 0;
}
运行结果:
运算符重载要求4-2-UnaryOperatorOverload
- 成员函数重载
Coordinate.h
#ifndef COORDINATE_H
#define COORDINATE_H
#include <iostream>
using namespace std;
class Coordinate
{
public:
Coordinate(int x,int y);
Coordinate & operator-(); // 声明运算符重载
int getX();
int getY();
private:
int m_iX;
int m_iY;
};
#endif
Coordinate.cpp
#include "Coordinate.h"
Coordinate::Coordinate(int x, int y)
{
m_iX = x;
m_iY = y;
}
int Coordinate::getX()
{
return m_iX;
}
int Coordinate::getY()
{
return m_iY;
}
// 运算符重载实现
Coordinate &Coordinate::operator-()
{
m_iX = -m_iX;
this->m_iY = -this->m_iY;
return *this;
}
main.cpp
#include "Coordinate.h"
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
Coordinate coor1(1, 3);
cout << coor1.getX() << "," << coor1.getY() << endl;
-coor1; //coor1.operator-()
cout << coor1.getX() << "," << coor1.getY() << endl;
system("pause");
return 0;
}
运行结果:
要求4-5-BinaryOperatorOverload
运算符的重载:对于加号运算符,输出运算符,索引运算符。
Coordinate.h
#ifndef COORDINATE_H
#define COORDINATE_H
#include <iostream>//包含了ostream
using namespace std;
class Coordinate
{
friend Coordinate &operator-(Coordinate &c);
friend Coordinate operator+(Coordinate c1,Coordinate c2);
friend ostream &operator<<(ostream &output, Coordinate &coor);
public:
Coordinate(int x,int y);
Coordinate &operator++();//前置++
Coordinate operator++(int);//后置++
//Coordinate operator+(Coordinate &c); // 成员函数重载加号
//其实里面有两个参数。
int operator [](int index);
int getX();
int getY();
private:
int m_iX;
int m_iY;
};
#endif
Coordinate.cpp
#include "Coordinate.h"
Coordinate::Coordinate(int x, int y)
{
m_iX = x;
m_iY = y;
}
int Coordinate::getX()
{
return m_iX;
}
int Coordinate::getY()
{
return m_iY;
}
Coordinate &operator-(Coordinate &c)
{
c.m_iX = -c.m_iX;
c.m_iY = -c.m_iY;
return c;
}
Coordinate &Coordinate::operator++()
{
m_iX++;
m_iY++;
return *this;
}
Coordinate Coordinate::operator++(int)
{
Coordinate old(*this);
this->m_iX++;
this->m_iY++;
return old;
}
//Coordinate Coordinate::operator+(Coordinate &c)
//{
// Coordinate temp(0, 0);
// temp.m_iX = this->m_iX +c.m_iX;
// temp.m_iY = this->m_iY +c.m_iY;
//
// return temp;
//}
Coordinate operator+(Coordinate c1, Coordinate c2)
{
Coordinate temp(0, 0);
temp.m_iX = c1.m_iX + c2.m_iX;
temp.m_iY = c1.m_iY + c2.m_iY;
return temp;
}
ostream &operator<<(ostream &output, Coordinate &coor)
{
output << coor.m_iX << "," << coor.m_iY;
return output;
}
int Coordinate::operator [](int index)
{
if (0 == index)
{
return m_iX;
}if (1 == index)
{
return m_iY;
}
}
main.cpp
#include "Coordinate.h"
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
Coordinate coor1(1, 3);
Coordinate coor2(2, 4);
Coordinate coor3(0, 0);
coor3 = coor1 + coor2;
//cout << coor3.getX() << "," << coor3.getY() << endl;
cout << coor3[0] <<endl;
cout << coor3[1] << endl;
system("pause");
return 0;
}
要求
5-2-FunctionTemplate
main.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
template <typename T>
void display(T a)
{
cout << a << endl;
}
template <typename T, class S>
void display(T t,S s)
{
cout << t << endl;
cout << s << endl;
}
template <typename T,int Ksize>
//该变量实例化时变为常量
void display(T a)
{
for (int i = 0; i < Ksize; i++)
{
cout << a << endl;
}
}
int main()
{
display<int>(10);
display<double>(10.98); // 模板函数
display<int,double>(5, 8.3);
display<int,3>(10);
system("pause");
return 0;
}
要求
5-6-ClassTemplate
MyArray.h:
#ifndef MYARRAY_H
#define MYARRAY_H
#include <iostream>
using namespace std;
template <typename T,int Ksize,int KVal>//模板参数列表
class MyArray
{
public:
MyArray();
~MyArray()
{
delete[]m_pArr;
m_pArr = NULL;
}//写在类内部的函数不需要注意什么。
void display();
private:
T *m_pArr;
};
template <typename T, int KSize, int KVal>
MyArray<T, KSize, KVal>::MyArray()
{
m_pArr = new T[KSize];
for (int i = 0; i < KSize; i++)
{
m_pArr[i] = KVal;
}
}
template <typename T,int KSize,int KVal>
void MyArray<T, KSize, KVal>::display()
{
for (int i = 0; i < KSize; i++)
{
cout << m_pArr[i] << endl;
}
}
#endif
MyArray.cpp
//什么都不写
main.cpp:
#include <stdlib.h>
#include <string>
#include "MyArray.h"
using namespace std;
int main()
{
MyArray<int, 5, 6> arr;//已经形成模板类了
arr.display();
system("pause");
return 0;
}
运行结果:
链表- 链表会有一个头结点。每一个链表都由若干结点组成。
- 一个结点都没有称之为空链表
- 存在多个结点。第一个结点称之为头结点。
- 对于每一个结点由两部分组成。一部分是数据部分(ABCDE都是数据域),还有一部分是指针部分。
- 指针部分用来将结点串联起来。
双链表:可以从头找到尾,也可以从尾找到头。
d 和 e中间插入数据,让d指向新数据,新数据指向e就可以了。
特点:数据插入速度快(不像向量,插入一个其他的全部都得后移)
使用方法上与数组基本相同。
map:映射
map映射键值映射一一对应,通过键找值.
map<int,string> m;//通过映射定义一个映射对象
pair<int,string> p1(10,"shanghai");//向映射中放入key&value
pair<int,string> p2(20,"beijing");
m.insert(p1); //将pair放入m中
m.insert(p2);
cout << m[10] << endl;//通过key访问值
cout << m[20] << endl;
map<string,string> m;//通过映射定义一个映射对象
pair<string,string> p1("S","shanghai");//向映射中放入key&value
pair<string,string> p2("B","beijing");
m.insert(p1);//将pair放入m中
m.insert(p2);
cout << m["S"] << endl;//通过key访问值
cout << m["B"] << endl;
标准模板库代码实现
标准模板库vector使用方法:
6-2-vectorPushBackPopFor
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;
int main()
{
vector<int> vec;
vec.push_back(3);//从尾部去插入
vec.push_back(4);
vec.push_back(6);
vec.pop_back();//从尾部去除一个
for (int i=0;i<vec.size();i++)
{
cout << vec[i] << endl;
}
cout << "end for" << endl;
cout << vec.size() << endl;
return 0;
}
运行结果:
迭代器版本: 6-2-2-IteratorVector
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;
int main()
{
vector<int> vec;
vec.push_back(3);//从尾部去插入
vec.push_back(4);
vec.push_back(6);
//迭代器
vector<int>::iterator itor = vec.begin();
//cout << *itor << endl; // 打印出来的是第一个元素值
for (;itor != vec.end();itor++)
{
cout << *itor << endl;
}
cout << "end iterator" << endl;
cout << vec.front() << endl;//第一个元素
cout << vec.back() << endl;//最后一个元素
return 0;
}
运行结果:
这里请注意end获取到的是最后一个元素的下一个位置
标准模版库编码实现2
list的遍历代码:
6-3-ListOnlyCanUseIterator
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;
int main()
{
list<int> list1;
list1.push_back(4);
list1.push_back(7);
list1.push_back(10);
// for (int i=0;i<list1.size();i++)
// {
// cout << list1[i] << endl;//错误
// }
return 0;
}
报错:
Type 'list<int>' does not provide a subscript operator
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;
int main()
{
list<int> list1;
list1.push_back(4);
list1.push_back(7);
list1.push_back(10);
// for (int i=0;i<list1.size();i++)
// {
// cout << list1[i] << endl;//错误
// }
list<int>::iterator itor = list1.begin();
for (;itor != list1.end();itor++)
{
cout << *itor << endl;
}
return 0;
}
map遍历:
6-3-MapIterator
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int,string> m;
pair<int,string> p1(3,"hello");
pair<int,string> p2(6,"world");
//m.push_back(p1); //错误,pushback不是map的成员
m.insert(p1);
m.insert(p2);
cout << m[3] << endl;
cout << m[6] << endl;
map<int,string>::iterator itor = m.begin();
for (;itor != m.end();itor++)
{
//cout << *itor << endl;//错误,每个都包含keyvalue
cout << itor->first << endl;
cout << itor->second << endl;
}
return 0;
}
运行结果:
string类型map
6-3-2-StringMap
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string,string> m;
pair<string,string> p1("H","hello");
pair<string,string> p2("W","world");
//m.push_back(p1);//错误
m.insert(p1);
m.insert(p2);
cout << m["H"] << endl;
cout << m["W"] << endl;
map<string,string>::iterator itor = m.begin();
for (;itor != m.end();itor++)
{
//cout << *itor << endl;//错误,每个都包含keyvalue
cout << itor->first << endl; //输出key
cout << itor->second << endl;//输出value
}
return 0;
}
运行结果:
- vector是对数组的封装,所以一旦对象被实例化,其大小就可以改变.大小可以根据元素数量改变
- list的特点是数据插入速度快。
- map需要与pair一起使用,用来存储多个key-value对。
- 不同厂商的标准模板库的实现细节可以不同,基本用法及原理相同。
单元巩固
使用vector存储数字3,6,8,4,并遍历。
使用map存储S-Shang Hai B-Bei Jing G-Guang Zhou,并遍历
6-5-VectorMapIterator
#include <vector>
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main(void)
{
// 使用vector存储数字:3、4、8、4
vector<int> vec;
vec.push_back(3);
vec.push_back(4);
vec.push_back(8);
vec.push_back(4);
//循环打印数字
vector<int>::iterator itor1 = vec.begin();
for(;itor1 != vec.end();itor1++)
{
cout << *itor1 <<endl;
}
// 使用map来存储字符串键值对
map<string, string> m;
pair<string, string> p1("S","Shang Hai");
pair<string, string> p2("B","Bei Jing");
pair<string, string> p3("G","Guang Zhou");
m.insert(p1);
m.insert(p2);
m.insert(p3);
// 打印map中数据
map<string, string>::iterator itor2 = m.begin();
for(;itor2 != m.end();itor2++)
{
cout << itor2->first <<endl;
cout << itor2->second <<endl;
}
return 0;
}
运行结果:
注意事项:
cout << itor2->first <<endl;
cout << itor2->second <<endl;
itor1和itor2不能重名。
网友评论