文章目录
C++模板篇
本章主要的内容:
- 友元函数、友元类
- 静态数据成员、静态成员函数
- 运算符重载
- 模板函数+模板类==》标准模板类
- 标准模板库中向量Vector、链表list、映射map的使用
**注意:**关于友元,友元只是封装的补充,会破坏封装性,有定向暴露性(在实在没有办法的情况下使用友元)
1.友元函数-全局友元函数和友元成员函数
1.全局友元函数的定义和调用:
class Time {
// Time类的全局友元函数
friend void printTime(Time &t);
public:
Time(int hour, int min, int sec) {
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
}
private:
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
};
// Time类的全局友元函数
void printTime(Time &t){
cout << t.m_iHour << ":"
<< t.m_iMinute << ":"
<< t.m_iSecond << endl;
}
int main() {
Time t(6,34,25);
printTime(t);// 调用全局友元函数
return 0;
}
/*输出:
6:34:25
*/
2.友元成员函数的定义和调用:
- Match类-Match.h:
//#include "Time.h"
// 先声明有Time,代表之后会进行实现,但是不能使用include,会导致循环包含
class Time;
class Match {
public:
void printTime(Time &t);
};
2.Match类-Match.cpp:
#include <iostream>
#include "Match.h"
#include "Time.h"// [!]不明白此处为何可以include,不会造成Match和Time的循环包含吗?
using namespace std;
void Match::printTime(Time &t) {
cout << t.m_iHour << ":"
<< t.m_iMinute << ":"
<< t.m_iSecond << endl;
}
3.Time类-Time.h:
#include <iostream>
#include "Match.h"
using namespace std;
class Time {
// 在这里声明友元函数,在此并不受本类的访问限定符限定,
// 故写在public或private下并没有区别
friend void Match::printTime(Time &t);
public:
Time(int hour,int min,int sec);
private:
int m_iHour;
int m_iMinute;
int m_iSecond;
};
4.Time类-Time.cpp:
#include "Time.h"
Time::Time(int hour, int min, int sec) {
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
}
5.main.cpp:
#include <iostream>
#include "Time.c"
int main() {
Time t(6,34,25);
Match m;
m.printTime(t);// 调用友元函数
return 0;
}
/*输出:
6:34:25
*/
2.友元类
友元类的写法:
由于编译器不同,友元类有两种写法:1、friend class 类名
; 2、friend 类名
。
友元类的声明与使用举例:
#include <iostream>
using namespace std;
// 事先加入Watch声明,代表当前没有实现,但是之后会进行实现
class Watch;
/**
* 定义Time类
* 数据成员:m_iHour, m_iMinute,m_iSecond
* 成员函数:构造函数
* 友元类:Watch
*/
class Time{
// 声明Time类是Match类的友元类,即声明Match有个友元类是Time
// 所以Match就可以访问Time中的成员了
friend class Watch;
public:
Time(int hour, int min, int sec){
m_iHour = hour;
m_iMinute = min;
m_iSecond = sec;
}
public:
int m_iHour;
int m_iMinute;
int m_iSecond;
};
/**
* 定义Watch类
* 数据成员:m_tTime
* 成员函数:构造函数
* display用于显示时间
*/
class Watch{
public:
Watch(Time &timeObj) : m_tTime(timeObj){
}
void display(){
cout << m_tTime.m_iHour << endl;
cout << m_tTime.m_iMinute << endl;
cout << m_tTime.m_iSecond << endl;
}
public:
Time m_tTime;
};
int main(){
Time t(6, 30, 20);
Watch w(t);
w.display();
return 0;
}
3.友元的总结
注意:
- 友元关系不可传递
- 友元关系得单向性(A是B的友元,不代表B是A的友元)
- 友元声明的形式及数量不受限制
- 友元只是封装的补充,会破坏封装性,有定向暴露性(在实在没有办法的情况下使用友元)
- 友元的声明不受访问限定符影响,可以声明在类中的任何位置。(即用
friend
修饰的声明,仅限被friend
修饰的这一句话不受)
对于友元关系的记法:
- 友元函数:friend在哪个类出现,则此函数就是这个类的朋友,这个函数就可以对这个类的所有数据成员进行访问了。(通过传入的对象的引用来进行访问)
- 友元类:friend在A类出现,则被
friend
修饰的B类就是这个类(A类)的朋友,所以B类就可以对A类中的所有数据成员进行访问了(直接通过B类进行调用即可,无需使用引用)。即在A类中出现friend修饰的B,那么B就是当前类的朋友,可以访问当前类。
4.静态变量与静态函数
静态成员依托于类,而不是对象,就算类没有实例化对象,静态成员也会存在于内存中。
假如有个类A,其中有静态变量cout,在实例化a,b,c,d之前,cout这个静态变量就已经存在于内存中 了。
静态变量:
声明:static int 变量名;
初始化(方法1):static int 变量名 = xxxx;
(在类中声明+初始化)
初始化(方法2):int 类名::变量名 = xxxx;
(在类外初始化)
访问(方法1):类名::变量名
访问(方法2):对象名.变量名
或指针名->变量名
静态函数:
初始化(方法1):static int 函数名(){xxxx;}
(在类中初始化)
访问(方法1):类名::函数名()
访问(方法2):对象名.函数名()
或指针名->函数名()
int 类名::变量名 = xxxx
注意事项:
- 静态数据成员必须单独初始化。(在对象实例化之前就有了,所以不能写到类的构造函数中去)
- 静态成员函数不能调用非静态成员函数和费静态数据成员。
- 静态数据成员只有一份,且不依赖对象而存在。
对于上面注意事项的第2点做一下原理补充:
在类中的普通成员函数中调用普通成员变量,实际上为了辨认出当前使用的变量属于哪个对象,都会自动添加this指针;如果是静态变量,因为不依托于对象,而是依托于类,所以不会自动添加this指针,如下所示:
void FunctionName(){
variable1 = "01"; // 普通成员变量
variable2 = "02"; // 静态成员变量
}
// 实际上会变成下面的这种形式
void FunctionName(ClassName *this){
this-