C++面向对象笔记(6):模板篇

C++模板篇

本章主要的内容:

  1. 友元函数、友元类
  2. 静态数据成员、静态成员函数
  3. 运算符重载
  4. 模板函数+模板类==》标准模板类
  5. 标准模板库中向量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.友元成员函数的定义和调用

  1. 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.友元的总结

注意:

  1. 友元关系不可传递
  2. 友元关系得单向性(A是B的友元,不代表B是A的友元)
  3. 友元声明的形式及数量不受限制
  4. 友元只是封装的补充,会破坏封装性,有定向暴露性(在实在没有办法的情况下使用友元)
  5. 友元的声明不受访问限定符影响,可以声明在类中的任何位置。(即用friend修饰的声明,仅限被friend修饰的这一句话不受)

对于友元关系的记法

  1. 友元函数:friend在哪个类出现,则此函数就是这个类的朋友,这个函数就可以对这个类的所有数据成员进行访问了。(通过传入的对象的引用来进行访问)
  2. 友元类: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

注意事项

  1. 静态数据成员必须单独初始化。(在对象实例化之前就有了,所以不能写到类的构造函数中去)
  2. 静态成员函数不能调用非静态成员函数和费静态数据成员。
  3. 静态数据成员只有一份,且不依赖对象而存在。

对于上面注意事项的第2点做一下原理补充:

在类中的普通成员函数中调用普通成员变量,实际上为了辨认出当前使用的变量属于哪个对象,都会自动添加this指针;如果是静态变量,因为不依托于对象,而是依托于类,所以不会自动添加this指针,如下所示:

void FunctionName(){
    variable1 = "01";	// 普通成员变量
    variable2 = "02";	// 静态成员变量
}
// 实际上会变成下面的这种形式
void FunctionName(ClassName *this){
    this->variable1 = "01";		// 会自动添加this指针
    variable2 = "02";			// 不会有this指针
}

静态成员函数中,因为这个函数不依托于对象,所以也不会有代表当前对象的this指针,所以如果使用普通成员变量,会不知道到底是哪个对象的成员变量,所以如果这样调用会报错,如下所示:

static int FunctionName(){
    // variable1是普通成员变量,variable2是静态成员变量
    variable1 = "01";	// 会报错!
    variable2 = "02";	//
}

但是普通的成员函数中使用静态的数据成员,则是完全没有问题。

静态成员函数和const常量修饰符:

禁止在静态函数后面加const,因为const的本质是实际是对隐藏的this指针加const,因为静态函数根本不存在this指针,所以会报错。

小总结

  1. 定义静态成员函数和静态数据成员都需要static关键字。

  2. 公有静态成员函数可以被类直接调用。

  3. 静态成员函数 既可以 访问非静态数据成员和静态数据成员,也可以调用非静态成员函数和静态成员函数静态成员函数只能访问静态数据成员和调用静态成员函数

  4. 静态数据成员不能在构造函数初始化,必须单独初始化。

5.一元运算符的重载

**运算符重载:**给原有运算符赋予新的功能。

**运算符重载的本质:**函数重载。

关键字:operator

-(负号)的重载,有两种重载的方法:

  1. 成员函数重载
  2. 友元函数重载

1.负号的重载-成员函数重载:

// 声明
class Coordinate{
public:
    Coordinate(int x,int y);
    
    // 成员函数实现负号重载,
    // 返回类型是Coordinate&,关键字是operator,
    // 函数名是-,无参数
    Coordinate& operator-();
    
private:
    int m_iX;
    int m_iY;
}

// 实现
Coordinate& Coordinate::operator-(){
    
    // 两种写法都可以,this指针可加可不加
    this->m_iX = -(this->m_iX);
    this->m_iY = -(this->m_iY);
    //m_iX = -m_iX;
    //m_iY = -m_iY;
    
    // 【为什么是*this?】
    // 这里我们的返回值是Coordinate对象的引用,这个引用该指向的是一个对象
    // 而this指针指向这个对象,所以我们要对this指针取值,从而获取到对象
    // 也就是使用“*this”
    return *this;
}

// 调用
int main(){
    Coordinate coor1(3,5);
    -coor1;		// 相当于coor1.operator-();
    return 0;
}

2.负号的重载-友元函数重载:

// 声明
class Coordinate{
    
    // 利用友元函数实现负号重载,
    // 友元函数也需要一个像成员函数自带的this一样的参数,
    // 故这里表现为Coordinate对象类型的参数,或引用
    // 即“Coordinate c”或“Coordinate &c”
    friend Coordinate& operator-(Coordinate& coor);
   
public:
    Coordinate(int x,int y);
private:
    int m_iX;
    int m_iY;
};

// 实现
// 注意:友元函数不属于Coordinate类,所以不能写成Coordinate::XXXX
Coordinate& operator-(){
    coor.m_iX = -coor.m_iX;
    coor.m_iY = -coor.m_iY;
    return *this;
}

// 调用
int main(){
    Coordinate coor1(3,5);
    -coor1;		// 相当于coor1.operator-();coor1这个对象会通过形参被传入
    return 0;
}

++符号(前置)的重载:

前置++:先++,再使用

// 声明
class Coordinate{
public:
    Coordinate(int x,int y);
    Coordinate& operator++(); // 前置++,返回当前对象的引用
private:
    int m_iX;
    int m_iY;
};

// 定义
Coordinate& Coordinate::operator++(){
    m_iX++;
    m_iY++;
    return *this;
}

// 调用
int main(){
    Coordinate coor1(3,5);
    ++coor1;		// coor1.operator++();
    return 0;
}

++符号(后置)的重载:

后置++:先使用,后++

// 声明
class Coordinate{
public:
    Coordinate(int x,int y);
    
    // 成员函数实现++(后置)重载,后面的int是一个标志,
    // int标志代表后置重载,没有为什么
    // 返回值也不再返回对象引用,而是返回一个对象
    Coordinate operator++(int); 
    
private:
    int m_iX;
    int m_iY;
};

// 实现
// 注意:这里的int代表后置,是个标志,不需要进行传值,之后也不会使用
Coordinate operator++(int){		
    
    // 将当前对象保存在临时对象中,这里会调用拷贝构造函数,
    // 作为返回,因为++后置是先使用,再++
    Coordinate old(*this);
    
    // 将当前对象中的属性进行++,如果之后再次调用此对象,就是++之后的值
    m_iX++;
    m_iY++;
    
    // 返回++之前的值
    return old;
}

// 调用
int main(){
    
    Coordinate coor1(3,5);
    coor1++; // coor1.operator++(0);系统会默认传入一个值到标志中,一般是0
    
    // 这样验证看得更清楚,会输出++之前的m_iX值
    cout << (coor1++).m_iX << ",";
    cout << (coor1++).m_iY << endl;
    
    return 0;
}

6.二元运算符的重载

+(加号)的重载,也有两种重载的方法:

  1. 成员函数重载
  2. 友元函数重载

对于此例来说,采用友元函数重载能说明得更加清楚。

1.加号的重载-成员函数重载:

// 声明
class Coordinate{
public:
    Coordinate(int x,int y);
    
    // 返回对象作为结果,参数是一个对象引用常量,
    // const是设计上的规范,我们在加的过程中并不希望修改加数本身的值
    Coordinate operator+(const Coordinate &coor);
    
private:
    int m_iX;
    int m_iY;
}

// 实现
Coordinate operator+(const Coordinate &coor){
    
    // 临时对象,用来保存相加的结果
    Coordinate temp;
    
    temp.m_iX = this->m_iX + coor.m_iX;
    temp.m_iY = this->m_iY + coor.m_iY;
    
    // 返回结果(临时对象)
    return temp;
}

// 调用
int main(){
    
    Coordinate coor1(3,5);
    Coordinate coor2(4,7);
    Coordinate coor3(0,0);
    
    coor3 = coor1 + coor2; // coor1.operator+(coor2);coor2前面还有一个隐藏参数,就是this指针,指向当前对象
    
    return 0;
}

2.加号的重载-友元函数重载:

// 声明
class Coordinate{
    
    // 加const是设计上的规范,我们在加的过程中并不希望修改加数本身的值
    friend Coordinate operator+(const Coordinate &c1,const Coordinate &c2);
    
public:
    Coordinate(int x,int y);
private:
    int m_iX;
    int m_iY;
}

// 实现
Coordinate operator+(const Coordinate &c1,const Coordinate &c2){
    
    // 临时对象,用来保存相加的结果
    Coordinate temp;
    
    temp.m_iX = c1.m_iX + c2.m_iX;
    temp.m_iY = c1.m_iY + c2.m_iY;
    
    return temp;
}

// 调用(和利用成员函数重载的调用一样,但过程略有不同)
int main(){
    
    Coordinate coor1(3,5);
    Coordinate coor2(4,7);
    Coordinate coor3(0,0);
    
    coor3 = coor1 + coor2; // operator+(coor1,coor2);
    
    return 0;
}

<<负号的重载:

这个用法也是规定的,和其他的略有不同。

**问题:**可以使用成员函数进行重载吗?不行,应该使用友元函数进行重载。

因为重载函数的第一个参数也必须是ostream&,所以不能用成员函数进行重载,因为成员函数的第一个参数是this指针(隐藏的)。

// 声明
class Coordinate{
    
    // 利用友元函数进行重载
    // 返回值必须是ostream&
   	// 第一个参数也必须是ostream&
    // 之后是要输出的对象
    friend ostream& operator<<(ostream &out,const Coordinate &coor);

public:
    Coordinate(int x,int y);
private:
    int m_iX;
    int m_iY;
}

// 实现
ostream& operator<<(ostream& out,const Coordinate& coor){
    
    // 将原来用cout的地方换成out
    out << coor.m_iX << "," << coor.m_iY;
    // 返回out
    return out;
}

// 使用
int main(){
    
    Coordinate coor(3,5);
    cout << coor; // operator<<(cout,coor);
    
    return 0;
}

[ ]索引运算符的重载:

**问题:**可以使用友元函数进行重载吗?不行,应该使用成员函数进行重载。

作为索引运算符来说,他的第一个参数必须是this指针,因为只有第一个参数是this指针,才能够传入索引,才能使这个索引所表达的是当前这个对象当中的成员。

但是友元重载,第一个参数可以是this指针,也可以是其他的值。所以不能使用友元函数进行重载。

// 声明
class Coordinate{
    
public:
    Coordinate(int x,int y);
    
    int operator[](int index);
    
private:
    int m_iX;
    int m_iY;
}

// 实现
int Coordinate::operator[](int index){
    
    if(0 == index){
        return m_iX;
    }
    if(1 == index){
        return m_iY;
    }
    // 还可以加其余索引的处理...
}

// 使用
int main(){
    
    Coordinate coor(3,5);
    cout << coor[0]; // coor.operator[](0);
    cout << coor[1]; // coor.operator[](1);
    
    return 0;
}

小总结:

  1. 运算符重载可以使运算符具有新的功能。
  2. 运算符重载使用关键字operator
  3. 所有的运算符都可以既使用友元函数重载和成员函数重载。有些运算符必须使用成员函数重载,有些则必须使用友元函数重载。
  4. 运算符重载需要区分前置++重载和后置++重载。

6.5.补充:运算符重载和友元函数的问题

为什么临时对象可以直接访问到私有成员?

头文件:

`class` `Coordinate {` `    ``// 利用友元函数进行+号重载``    ``friend` `Coordinate operator+(``const` `Coordinate c1,``const` `Coordinate c2);` `public``:``    ``// 构造函数,带初始化参数``    ``Coordinate(``int` `x,``int` `y);` `    ``int` `getX();``    ``int` `getY();` `private``:``    ``// 私有属性``    ``int` `m_iX;``    ``int` `m_iY;``};`

cpp文件:

`#include "Coordinate.h"` `Coordinate operator+(Coordinate c1,Coordinate c2){` `    ``Coordinate temp(0,0);` `    ``temp.m_iX = c1.getX() + c2.getX();``    ``temp.m_iY = c1.getY() + c2.getY();` `    ``return` `temp;``}`

为何这里可以直接使用 temp.m_iX ?

答案:

对象直接访问自己的私有成员这种用法绝对是错的,不要这么使用。可以借助友元类/友元函数类自己的成员函数进行访问。

我们在Coordinate类中声明了友元函数operator+(),友元函数在访问权限上和类内函数比较相似,可以对这个类的所有数据成员进行访问。

// 验证友元函数中创建的对象是否可以访问自己的私有成员。
// 结论:可以
 
#include <iostream>
 
using namespace std;
 
class hehe{
 
    // hehe类的友元函数
    friend void heheFriend(hehe &h);
 
public:
    int getxx(){ return xx; }
    int getyy(){ return yy; }
private:
    int xx;
    int yy;
};
 
void heheFriend(hehe &h){
 
    // 友元函数可以访问类的所有成员,包括私有
    h.xx = 1;
    h.yy = 2;
 
    // 【友元函数中创建的对象h2可以访问自己的私有成员】
    hehe h2;
    h2.xx = h.xx;
    cout << "h2.xx = " << h2.xx << endl;
}
 
 
int main() {
 
    hehe h1;
 
    // 无法直接访问私有成员
    //h1.xx; // 错误提示:'xx' is a private member of 'hehe'
    //h1.yy; // 错误提示:'yy' is a private member of 'hehe'
 
    // 调用友元函数,进行函数成员赋值
    heheFriend(h1);
    cout << "h1.xx = " << h1.getxx() << endl;
 
    return 0;
}
/*
 * 输出结果:
 * h2.xx = 1
 * h1.xx = 1 
 */

7.函数模板

函数模板和类模板关键字:

templatetypenameclass,其中 typenameclass起到的作用是相同的,并且可以混用。

关键字的使用1:

// 函数模板
// 通过template声明函数的模板
// 通过class来声明一个参数,这个参数就能表明这是一种类型
template <class T>
T max(T a, T b){
    return (a>b)?a:b;
}

// 模板函数(模板的使用),通过函数模板生产出来的函数
int ival = max(100,99); // 自动生成int数据类型
char cval = max<char>('A','B'); // 用<char>指定数据类型

关键字的使用2:

// 函数模板
template <class T>
void swap(T &a,T &b){
	T tmp = a; a = b; b = tmp;    
}

// 模板函数
int x = 20,y = 30;
swap<int>(x,y); // 用<int>指定数据类型

变量作为模板参数:

// 函数模板
template <int size>
void display(){
	cout << size << endl;
}

// 模板函数
display<10>();

多参数函数模板:

// 函数模板
// 后面的typename也不能省略
template <typename T,typename C>
void display(T a,C b){
    cout << a << " " << b << endl;
}

// 模板函数
int a = 1024;string str = "hello world!";
display<int, string>(a,str);

函数模板定义中的混用:

// typename和class混用
template <typename T,class >

// 和变量混用
template <typename T,int size>
void display(T a){
	for(int i = 0;i < size;i++){
		cout << a << endl;
	}
}
display<int,5>(15);

小总结:

  1. 函数模板的参数个数可以是一个也可以是多个。(模板的参数是指<>中的内容)
  2. 函数模板的参数个数可以为零个不可以为零个参数,参数个数如果为0个,则没有必要使用函数模板。
  3. 使用函数模板时,需要指定模板参数,此时的函数称为模板函数。
  4. 当需要定义多个功能相同,数据类型不同的函数时,可以使用函数模板来定义。

8.类模板

类模板的.h和.cpp文件:

在C++中,模板代码不能分离编译(不能写成.h+.cpp这种形式,只能把所有的代码都写在.h文件中使用),不然部分编译器无法通过编译。在使用的时候,只需要把.h文件include
""进当前程序中。

类模板的定义与使用1:

template<class T>

class MyArray{
public:
    // 1.类内定义
    void display();
private:
    T *m_pArr;
}
// 2.类外定义
// 类外定义类名后面需要添加<>
// 每定义一个成员函数,都要在这个成员函数前面添加template<......>
template<class T>
void MyArray<T>::display(){
    ......
}

// 使用
int main(){
    
    MyArray<int> arr;
    arr.display();
    return 0;
}

类模板的定义与使用2:

写的时候需要特别注意各种修饰符、限定符、返回值类型,很容易写错。

#include <iostream>
using namespace std;

/**
 * 定义一个矩形类模板Rect
 * 成员函数:calcArea()、calePerimeter()
 * 数据成员:m_length、m_height
 */
template<typename T>
class Rect
{
public:
    Rect(T length,T height);
    T calcArea();
    T calePerimeter();
public:
	T m_length;
	T m_height;
};

/**
 * 类属性赋值
 */
template<typename T>
Rect<T>::Rect(T length,T height)
{
	m_length = length;
	m_height = height;
}

/**
 * 面积方法实现
 */
template<typename T>
T Rect<T>::calcArea()
{
	return m_length * m_height;
}

/**
 * 周长方法实现
 */
template<typename T>
T Rect<T>::calePerimeter()
{
	return ( m_length + m_height) * 2;
}

// 使用
int main(void)
{
	Rect<int> rect(3, 6);
	cout << rect.calcArea() << endl;		// 输出:18
	cout << rect.calePerimeter() << endl;	// 输出:18
	return 0;
}

小总结:

  1. 定义一个类模板就相当于定义了一系列功能相同类型不同的类。
  2. 定义类模板需要使用关键字template。
  3. 定义类模板的参数可以使用typename和class,但不能混用可以混用
  4. 模板参数既可以是类型,也可以是变量。

9.标准模板库STL(Standard Template Lib)

vector向量

**本质:**对数组的封装

**特点:**读取快速,读取能在常数时间内完成,数据插入慢,如果插入数据,后面数据的位置都要移动。

初始化:

[外链图片转存失败(img-8yBYgdSb-1563352671639)(./images/muke_C++/014.png)]

常用操作:

[外链图片转存失败(img-Wy4kKhuO-1563352671640)(./images/muke_C++/015.png)]

向量的遍历:

除了在for、while中使用下标进行遍历,还可以使用迭代器

// for遍历
for(int i = 0;i < vec.size();i++){
    cout << vec[i] << endl;
}

迭代器(iterator)及其使用方法:

int main(){
    
    vector vec;
    vec.push_back("hello");
    
    // 定义、初始化迭代器iterator
    vector<string>::iterator citer = vec.begin();
    // 使用迭代器遍历向量
    for( ;citer != vec.end();citer++){
        cout << *citer << endl;
    }
    
    return 0;
}

链表(list)

**特点:**数据插入速度快,查询较慢。

操作和vector向量类似,也可以使用迭代器,但不能用下标循环遍历。

映射(map)

键值对,有点类似数组。

// 创建一个映射
map<int,string> m;

// 创建映射关系
pair<int,string> p1(10,"shanghai");
pair<int,string> p2(20,"beijing");

// 将创建的映射关系插入映射中
m.insert(p1);
m.insert(p2);

// 调用映射
cout << m[10] << endl;
cout << m[20] << endl;

也可以使用字符串作为索引:

map<string,string> m;

pair<string,string> p1("SH","shanghai");
pair<string,string> p2("BJ","beijing");

m.insert(p1);
m.insert(p2);

cout << m["SH"] << endl;
cout << m["BJ"] << endl;

映射的遍历:

**注意:**打印是按索引(key)的顺序打印的,如“A”,先于“B”打印。

// 使用迭代器进行遍历
map<int,string>::iterator itor = m.begin();
for(;itor != m.end();itor++){
    cout << itor->first << endl;	// 输出key
    cout << itor->second << endl;	// 输出value
    cout << endl;
}

小总结:

  1. vector是对数组的封装,所以一旦对象被实例化,其大小就不能改变了 大小可以根据元素数量改变
  2. list的特点是数据插入速度快。
  3. map需要与pair一起使用,用来存储多个key-value对。
  4. 不同厂商的标准模板库的实现细节可以不同,基本用法及原理相同。

练习:

// 使用vector存储数字3,6,8,4,并遍历。
// 使用map存储S-Shang Hai   B-Bei Jing    G-Guang Zhou,并遍历
#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 citer = vec.begin();
    for( ; citer != vec.end(); citer++){
        cout << *citer << 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 citer2 = m.begin();
    for( ; citer2 != m.end(); citer2++){
        cout << citer2->first << endl;	// key
        cout << citer2->second << endl;	// value
    }
    
    return 0;
}
/* 输出:
3
4
8
4
B
Bei Jing
G
Guang Zhou
S
Shang Hai
*/

**注意:**打印是按索引(key)的顺序打印的,如“A”,先于“B”打印。

本篇为视频教程笔记,视频如下:

C++远征之模板篇

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值