首页 > 编程语言 >C++提高

C++提高

时间:2022-10-03 17:03:07浏览次数:50  
标签:函数 int 提高 C++ template include void 模板

C++提高编程

本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层的使用

1、模板

1.1 模板的概念

模板就是建立通用的模具,大大提高复用性

模板的特点:

  • 模板不可以直接使用,它只是一个框架
  • 模板的通用并不是万能的

1.2 函数模板

  • C++另一种编程思想称为泛型编程,主要利用的技术就是模板
  • C++提供两种模板机制:函数模板类模板

1.2.1 函数模板语法

函数模板作用:

建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。

语法:

template<typename T>
函数声明或定义  // 定义函数模板前面都要加上上面那一行

解释:

template -- 声明创建模板

typename -- 表明其后面的符号是一种数据类型,可以用class代替

T -- 通用的数据类型,名称可以替换,通常为大写字母

#include<iostream>
#include<string>	
using namespace std;


// 定义一个交换的函数模板  
template<typename T>   // 声明一个模板,告诉编译器后面代码中紧跟着的T不要报错, T是一个通用数据类型
void swap1(T& a, T& b) {
	T tmp;
	tmp = b;
	b = a;
	a = tmp;
}

void test() {
	int a = 10;
	int b = 20;
	// 两种方式使用函数模板
	// 1、自动类型推导  不填类型,让其自己推导,但是不能使用不同的类型
	//swap1(a, b);

	// 2、显示指定类型  用< >指定具体的数据类型
	swap1<int>(a, b);
	cout << a << "\t" << b << endl;
}

int main() {
	test();
	system("pause");
	return 0;
}
template <class T, class M>
void print(T a, M b) {
	cout << a <<"\t" << b << endl;
}

int a = 10;
int b = 10;
char c = 'c';
print(a, c);
print<int>(a, c);  // 指定第一个,即T类型
print<int, int>(a, c);

1.2.2函数模板注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型才可以使用
  • 模板必须要确定出T的数据类型, 才可以使用

1、

	int a = 10;
	int b = 20;
	char c= "c";
	// 1、自动类型推导  下面这种事错误的,因为无法确定是int还是char
	//swap1(a, c);

2、模板必须要确定出T的数据类型, 才可以使用,就是有的函数可能就没有传输可以让其识别T数据类型的参数,无法确定其数据类型,这种就不能用自动类型推导,而是直接给确定一种数据类型

template <typename T>
void func(){
	cout<<"func调用,无法通过自动类型推导确定T的数据类型";
}

void test(){
	//func() //错误,无法调用,因为模板无法确定T的数据类型
	//调用方法,第二种方式
	func<int>()  // 指定一种数据类型

}

1.2.3函数模板案例

案例描述:

  • 利用函数模板封装一个排序函数,可以对不同类型数组进行排序
  • 排序规则从大到小,排序算法为选择排序
  • 分别用char数组和int数组进行测试
#include<iostream>
#include<string>	
using namespace std;


// 定义一个交换的函数模板  
template<typename T>   // 声明一个模板,告诉编译器后面代码中紧跟着的T不要报错, T是一个通用数据类型
void swap1(T& a, T& b) {
	T tmp;
	tmp = b;
	b = a;
	a = tmp;
}

template <class T>
void selectSort(T Arr[],  int len) {
	for (int i = 0; i < len-1; i++) {
		int local = i;
		for (int j = i; j < len; j++) {
			if (Arr[j] > Arr[local]) {
				local = j;
			};
		}
		swap1(Arr[i], Arr[local]);
	}
}


// 打印数组的模板
template <class T>
void print_list(T Arr[], int len) {
	for (int i = 0; i < len; i++) {
		cout << Arr[i];
	}
	cout << endl;
}

void test1() {

	int int_arr[] = { 9,7,8,5,4,2,3,1,0 };
	char char_arr[] = "abcgdwert";
	//int len = sizeof(Arr) / sizeof(Arr[0]);
	selectSort(int_arr, sizeof(int_arr) / sizeof(int_arr[0]));
	selectSort(char_arr, sizeof(char_arr) / sizeof(char_arr[0]));

	print_list(int_arr, sizeof(int_arr) / sizeof(int_arr[0]));
	print_list(char_arr, sizeof(char_arr) / sizeof(char_arr[0]));
	
}

int main() {
	test1();
	system("pause");
	return 0;
}

1.2.4普通函数与函数模板的区别

  • 普通函数调用时可以可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显式指定的方式,可以发生隐式类型转换
int add(int a, int b) {
	
	return a + b;
}

template <class T>
T add_T(T a, T b) {
	return a + b;
}


void test2() {
	int a = 10;
	int b = 10;
	char c = 'c';
	cout<<add(a, c)<<endl;  // 发生隐式转换,将c转换为整型ascll码
	//add_T(a, c);  // 报错,自动类型转换,不支持隐式类型转换
	add_T<int>(a, c); // 显式支持
}

总结:建议使用显式指定类型的方式,调用函数模板,因为可以自己确定通用类型T

1.2.5普通函数与函数模板的调用规则

如下:(重载的情况下)

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表<>来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以产生更好的匹配,优先调用函数模板
//普通函数
void myPrint(int a, int b) {
	cout << "调用普通函数" << 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 test2() {
	int a = 10;
	int b = 20;
	// 1、优先调用普通函数
	myPrint(a, b);
	// 2、强制调用模板
	myPrint<>(a, b);
	// 3、模板重载
	myPrint(a, b, 10);
	// 4、函数模板可以产生更好的匹配,优先调用函数模板
	char c = 'c';
	char d = 'd';
	myPrint(c, d);


	/*调用普通函数
	调用模板函数
	调用重载模板函数
	调用模板函数*/
}

1.2.6模板的局限性

局限性:

  • 模板的通用性并不是万能的
template <class T>
void func(T a, T b) {
	a = b;
}

在上述代码中提供的赋值操作,如果传入的是a和b是一个数组,就无法实现了

再如

template <class T>
void func(T a, T b){
    if (a>b){
        .....
    }
}

在上述代码中,如果T的数据类型传入的是自定的数据类型,如类,结构体,也无法正常运行

因此C++为了解决这样的问题,提供了模板的重载,可以为这些特定的数据类型,提供具体化的模板

#include<iostream>
#include<string>	
using namespace std;
#include<string>

class Person {
public:
	string m_name;
	int m_age;
};

template<class T>
bool myCompare(T &a, T &b) {
	if (a == b) { return true; }
	else { return false; }
}

// 利用具体化Person的版本实现代码,具体化优先调用  把上面的bool myCompare(T &a, T &b)
// 复制过来,把T具体化, 然后前面加上 template<>  说明这是一个模板的重载,
template<> bool myCompare(Person& p1, Person& p2) {
	if (p1.m_name == p2.m_name && p1.m_age == p2.m_age) { return true; }
	else { return false; }
}


void test2() {
	Person p1 = { "xiaoming", 18 };
	Person p2 = { "xiaoming", 18 };
	cout << myCompare<Person>(p1, p2) << endl;
}

int main() {
	test2();
	system("pause");
	return 0;
}

1.3 类模板

1.3.1类模板语法

类模板作用:

  • 建立一个通用类,类中的成员 数据类型可以不具体指定,用一个虚拟的类型来代表

**语法: **

template<class T>
类

解释:

template: 声明创建模板

typename : 表明其后面符号是一种数据类型,可用class代替

T : 通用数据类型,名称可以替换,通常为大写字母24

template <class NameType, class AgeType>
class Person {	
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson() {
		cout << "姓名" << m_name << "\t" << "年龄:" << m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};




void test3() {
	Person<string, int>p1("孙悟空", 2000);  //类模板必须有参数列表,也就是说不能使用自动推导数据类型
	p1.showPerson();
}

总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板

1.3.2类模板与函数模板区别

类模板与函数模板区别主要有两点:

  1. 类模板没有自动类型推导的使用方式
  2. 类模板在模板参数列表中可以有默认参数
template <class NameType = string, class AgeType=int>
class Person{....}
....
Person p("猪八戒", 2000); // 不用参数列表指定,使用默认参数类型


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

类模板中成员函数和普通类中成员函数创建时机是有区别的:

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建
// 普通类
class Person1 {
public:
	void showPerson1() {
		cout << "person 1" << endl;
	}
};
class Person2 {
public:
	void showPerson2() {
		cout << "person 2" << endl;
	}
};

template <class T>
class MyClass {
public:
	T obj;
	void func1() { obj.showPerson1(); }
	void func2() { obj.showPerson2(); }
};


void test3() {
	MyClass<Person1>m;
	m.func1();
	m.func2();  // 在不调用的时候,不报错,调用的时候才报错,说明函数调用时候才会创建函数
}

总结:类模板中的成员函数兵部使一开始就创建的,在调用时才去创建

1.3.4类模板对象做函数对象

学习目标:

  • 类模板实例化出的对象,像函数传参的方式

一共有三种传入方式

  1. 指定传入的类型 : 直接显示对象的数据类型
  2. 参数模板化 : 将对象中的参数变为模板进行传递
  3. 整个类模板化 : 将这个对象类型 模板化进行传递
#include<iostream>
#include<string>	
using namespace std;
#include<string>


template <class NameType, class AgeType=int>
class Person {	
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson() {
		cout << "姓名:" << m_name << "\t" << "年龄:" << m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};

// 第一种 传入方式  指定传入类型
void func1(Person<string>& p) {
    
	p.showPerson();
}

// 第二种 传入方式  参数模板化
template<typename T>
void func2(Person<T>& p) {
    cout<<T的数据类型<<typeid(T).name()<<endl;
	p.showPerson();
}

// 第三种 整个类模板化
template <class T>
void func3(T& p) {
	p.showPerson();
}

void test3() {
	Person<string>p("孙悟空", 5000);
	func1(p);
	func2(p);
	func3(p);
}

int main() {
	test3();
	system("pause");
	return 0;
}

总结:

  • 通过类模板创建的对象,可以有三种方式向函数中进行传参
  • 使用比较广泛的时第一种:指定传入的类型

1.3.5类模板与继承

当类模板碰到继承,需要注意以下几点

  • 当子类继承的父类是一个类模板的时候,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果向灵活指定出父类中T的类型,子类也需要变为类模板
#include<iostream>
#include<string>	
using namespace std;
#include<string>


template<class T>
class Base {
public:
	T m;
};


//继承方式一  指定父类中T的数据类型
class Son :public Base<int> {
public:
	Son(int m) {
		this->m = m;
		cout << this->m << endl;
	}
};

// 二、将子类也变为类模板,T2 指向父类中的T
template <class T1, class T2>
class Son2 :public Base<T2> {
public:
	Son2(T1 n, T2 m) {
		this->m = m;
		this->n = n;
		cout << this->m << "\t" << this->n << endl;
	}
	T1 n;
};


void test4() {
	Son s1(10);
	Son2 <int, int>s2(10, 20);
}

int main() {
	test4();
	system("pause");
	return 0;
}

总结:如果父类是类模板,子类需要指定出父类中的T的数据类型

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

目标:找我类模板中成员函数的类外实现

  • 需要在类外实现 的函数名上一行加模板的声明 说明是一个模板
  • 在函数名前加作用域
  • 作用域后加参数列表,说明是一个模板类
#include<iostream>
#include<string>	
using namespace std;
#include<string>


template<class T1, class T2>
class Base {
public:
	Base(T1 name, T2 age);
	void show();

	T1 m_name;
	T2 m_age;
};

// 构造函数类外实现
template<class T1, class T2>
Base<T1, T2> ::Base(T1 name, T2 age) {
	this->m_name = name;
	this->m_age = age;
}


template <class T1, class T2>
void Base<T1, T2>::show() {
	cout << "姓名:" << this->m_name << endl;
	cout << "年龄:" << this->m_age << endl;
}


void test4() {
	Base<string, int> b("chen", 18);
	b.show();
}

int main() {
	test4();
	system("pause");
	return 0;
}

总结: 类模板中成员函数类外实现,需要加上模板参数列表

1.3.7类模板分文件编写

目标:掌握类模板成员函数分文件编写产生的问题及解决方式

问题:

  • 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

  • 解决方式1:直接包含cpp源文件, cpp源文件中 会包含.h 文件
  • 解决方式2:将声明和实现写到同一个文件中,并更改后缀名.hpp,hpp是约定俗成的名称,不是强制

解决方式1:

#include"base.cpp"

解决方式2:

// hpp文件
#pragma once
#include<iostream>
#include<string>	
using namespace std;
#include<string>

template<class T1, class T2>
class Base {
public:
	Base(T1 name, T2 age);
	void show();

	T1 m_name;
	T2 m_age;
};


template<class T1, class T2>
Base<T1, T2> ::Base(T1 name, T2 age) {
	this->m_name = name;
	this->m_age = age;
}


template <class T1, class T2>
void Base<T1, T2>::show() {
	cout << "姓名:" << this->m_name << endl;
	cout << "年龄:" << this->m_age << endl;
}



// 主文件
#include"Base.hpp"

void test4() {
	Base<string, int> b("chen", 18);
	b.show();
}

总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp

1.3.8类模板与友元

目标:掌握类模板配合友元函数的类和类外实现

  • 全局函数类内实现,直接在类内声明友元即可
  • 全局函数类外实现,需要提前让编译器知道全局函数的存在
#include<iostream>
#include<string>	
using namespace std;
#include<string>

// showPerson2中需要有Person类所以要声明
template <class NameType, class AgeType = int>
class Person;

// 类外实现 所以要让编译器知道这个函数的存在,所以要放在前面
template <class NameType, class AgeType = int>
void showPerson2(Person<NameType, AgeType>p) {
	cout << "姓名:" << p.m_name << "\t" << "年龄:" << p.m_age << endl;
}

template <class NameType, class AgeType = int>
class Person {
	// 1、全局函数类内实现
	friend void showPerson(Person<NameType, AgeType>p) {
		cout << "姓名:" << p.m_name << "\t" << "年龄:" << p.m_age << endl;
	}
	// 2、全局函数 类外实现
	// 加空模板参数列表 表明是一个函数模板
	// 如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
	friend void showPerson2<>(Person<NameType, AgeType>p);
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}

private:
	NameType m_name;
	AgeType m_age;
};


void test5() {
	Person <string, int> p("孙悟空", 5000);
	showPerson(p);
}

int main() {
	test5();
	system("pause");
	return 0;
}

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别

1.3.9类模板案例

案例描述:实现一个通用的数组类,要求如下

  • 可以对内置数据类型以及自定义数据类型的数据进行存储
  • 将数组中的数据存储到堆区
  • 构造函数中可以传入数组的容量
  • 提供对应的拷贝构造函数以及operator= 防止浅拷贝问题
  • 提供尾插法和尾删法对数组中的数据进行增加和删除
  • 可以通过下标的方式访问数组中的元素
  • 可以获取数组中当前元素的个数和数组的数量

MyArr.hpp

#pragma once
#include<iostream>
using namespace std;

#include<string>	


template<class T>
class MyArr {
public:
	// 构造函数
	MyArr(int capacity) {
		cout << "有参构造函数" << endl;
		this->m_capacity = capacity;
		this->m_size = 0;
		this->pAddress = new T[this->m_capacity];
	}
	// 拷贝构造
	MyArr(const MyArr& arr) {
		cout << "拷贝构造函数" << endl;
		this->m_capacity = arr.m_capacity;
		this->m_size = arr.m_size;
		// 深拷贝
		this->pAddress = new T[arr.m_capacity];
		for (int i = 0; i < m_size; i++) {
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	// operator= 运算符重载  防止浅拷贝问题
	MyArr& operator=(MyArr& arr) {
		cout << "operator=重载" << endl;
		// 先判断原来堆区是否有数据, 如果有先释放
		if (this->pAddress != NULL) {
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_capacity = 0;
			this->m_size = 0;
		}
		this->m_capacity = arr.m_capacity;
		this->m_size = arr.m_size;
		this->pAddress = new T[arr.m_capacity];
		for (int i = 0; i < arr.m_size; i++) {
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}

	// 尾插法对数组中数据进行增加  const修饰的常量指针 支持非左值输入 指向的值不发生变化
	void append(const T& val) {
		if (this->m_capacity == this->m_size) {
			cout << "数组内存已满" << endl;
			return;
		}
		else {
			this->pAddress[this->m_size] = val;
			this->m_size++;
		}
	}

	// 尾删法对数组中数据进行删除
	void pop() {
		// 让用户访问不到最后一个元素,即是尾删
		if (this->m_size == 0) {
			return;
		}
		this->m_size--;
	}


	// 通过下标访问数组中元素
	T& operator[](int index){
		return this->pAddress[index];
	}

	// 返回数组容量
	int getCapacity() {
		return this->m_capacity;
	}

	// 返回数组容量
	int get_size() {
		return this->m_size;
	}

	~MyArr()
	{
		cout << "析构函数" << endl;
		if (this->pAddress != NULL) {
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}

private:
	T* pAddress;
	int m_capacity;
	int m_size;
};

主函数

#include"MyArr.hpp"


void test6() {
	MyArr<int>arr1(10);
	MyArr<int>arr2(arr1);
	MyArr<int>arr3(20);
	
	arr1.append(1);
	arr1.append(2);
	arr1.append(3);
	arr1.append(4);
	arr3 = arr1;
	cout << arr3[3] << endl;
	arr3[2] = 10;
	cout << arr3[2] << endl;
	cout << arr3.getCapacity() << endl;
	cout << arr1.get_size() << endl;
}

int main() {
	test6();
	system("pause");
	return 0;
}

2、STL初识

2.1 STL诞生

2.2 STL基本概念

  • STL(standard Template Library 标准模板库)
  • STL从广义上分为:容器container 算法algorithm 和迭代器 iterator
  • 容器和算法之间通过迭代器进行无缝连接
  • STL几乎所有的代码都采用了模板类或者模板函数

2.3 STL六大组件

STL大体分为六大组件, 分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  1. 容器:各种数据结构,如vector、list、deque、set、、map等,用来存储数据
  2. 算法:各种常用的算法 如sort、find、copy、for_each等
  3. 迭代器:扮演了容器与算法之间的胶合剂
  4. 仿函数:行为类似函数,可作为算法的某种策略
  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
  6. 空间配置器:负责空间的配置与管理

2.4 STL中容器、算法、迭代器

容器:存放各种数据

STL容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组、链表、数、栈、队列、集合、映射表等

这些容器分为序列式容器关联式容器两种:

序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置

关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

算法:解决问题的方法

有限的步骤,解决逻辑或者数学上的问题 algorithms

算法分为质变算法非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容,如拷贝、替换、删除等

非质变算法:是值运算过程中国不会更改区间内的元素内容,如查找、计数、遍历、寻找极值等

迭代器:容器和算法之间的粘合剂

提供一种方法,是指能够依次寻访,某个容器所含的各个元素,而又无须暴露该容器的内部表示方式

每个容器都有自己专属的迭代器

迭代器的使用非常类似于指针,初学阶段我们可以先理解迭代器为指针

迭代器种类

种类 功能 支持运算
输入迭代器 对数据的只读访问 只读,支持++、++、!+
输出迭代器 对数据只写访问 只写 支持 ++
前向迭代器 读写操作,并能向前推进迭代器· 读写
双向迭代器 读写操作,并能向前和向后操作 读写
随机访问迭代器 读写操作,可以以跳跃式的方式访问任意数据,功能最强的迭代器 读写支持++、--、[n]、-n、<、<=、>=、>

常用的容器中迭代器种类为双向迭代器和随机访问迭代器

2.5容器算法迭代器初识

STL中最常用的容器为Vector,可以理解为数组

2.5.1vector存放内置数据类型

容器:vector 就是一个模板类,创建即实例化的时候要加参数列表

算法:for_each(起始位置,终止位置,执行的函数(不加括号)) 需要头文件algorithm

迭代器:vector<int>::iterator 指向第一个元素位置 .begin() 最后一个元素的下一个位置 .end()

#include<iostream>	
#include<string>	
#include<vector>
using namespace std;
#include<algorithm>  // 标准算法头文件

template <class T>
void myPrint(T val) {
	cout << val << endl;
}

void test() {
	// 创建一个vector容器, 数组 ,容器中数据类型为int
	vector<int>v;
	// 尾插法添加数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);
	//通过迭代器访问容器中的数据
	vector<int>::iterator itBegin = v.begin(); // 起始迭代器  指向容器中的第一个元素
	vector<int>::iterator itEnd = v.end(); // 结束迭代器  指向容器中最后一个元素的下一个位置

	//// 第一种遍历方式
	//while (itBegin != itEnd) {
	//	cout << *itBegin << endl;
	//	itBegin++;
	//}
	
	// 第二种遍历方式
	/*for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << endl;
	}*/

	// 第三种遍历方式
	for_each(v.begin(), v.end(), myPrint<int>);  // 利用标准STL提供的遍历算法
}

int main() {
	test();
	system("pause");
	return 0;
}
2.5.2Vector存放自定义数据类型

vector中存放自定义数据类型, 并打印输出

#include<iostream>	
#include<string>	
#include<vector>
using namespace std;
#include<algorithm>  // 标准算法头文件


// 定义自定数据类型  类
class Person {
public:
	Person(string name, int age) {
		this->mName = name;
		this->mAge = age;
	}

	string mName;
	int mAge;
};

void test() {
	vector<Person> v;
	Person p1("孙悟空", 399999);
	Person p2("sunwukong", 399999);
	Person p3("zhubajie", 3434341);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	
	// 遍历打印
	vector<Person>::iterator it_begin = v.begin();
	vector<Person>::iterator it_end = v.end();

	/*while (it_begin != it_end) {
		cout << it_begin->mName << "  " << it_begin->mAge << endl;
		cout << (*it_begin).mName << "  " << (*it_begin).mAge << endl;
		it_begin++;
	}*/

	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
		cout << it->mName << "  " << it->mAge << endl;
	}
}

void test2() {
	//存放自定义数据类型 指针
	vector<Person*> v;
	Person p1("孙悟空", 399999);
	Person p2("sunwukong", 399999);
	Person p3("zhubajie", 3434341);
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);

	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
		cout << (**it).mName << "  " << (**it).mAge << endl;
		cout << (*it)->mName << "  " << (*it)->mAge << endl;
	}
}

int main() {
	//test();
	test2();
	system("pause");
	return 0;
}
2.5.3vector 容器嵌套容器

vector中嵌套容器, 将所有的数据进行遍历输出

#include<iostream>
#include<string>	
using namespace std;
#include<vector>	

void test() {
	// 嵌套一个vector int类型的容器
	vector<vector<int>> v;
	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	// 添加数据
	for (int i = 0; i < 3; i++) {
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
	}
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);

	// 遍历
	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) {
		// it指向嵌套的容器的地址,需要*取出,然后再用其迭代器,取出里面的值
		for (vector<int>::iterator vit = it->begin(); vit != (*it).end(); vit++) {
			cout << *vit << endl;
		}
	}


}

int main() {
	test();
	system("pause");
	return 0;
}

标签:函数,int,提高,C++,template,include,void,模板
From: https://www.cnblogs.com/fuxingming/p/16750734.html

相关文章

  • 「浙江理工大学ACM入队200题系列」问题 K: 零基础学C/C++84——奇偶ASCII值判断
    本题是浙江理工大学ACM入队200题第八套中的K题我们先来看一下这题的题面.题面题目描述任意输入一个字符,判断其ASCII是否是奇数,若是,输出YES,否则,输出NO;例如,字符A的AS......
  • 第十三届蓝桥杯C++B组国赛C题——卡牌 (AC)
    参赛话题:​​算法题解​​目录​​1.卡牌​​​​1.问题描述​​​​2.输入格式​​​​3.输出格式​​​​4.样例输入​​​​5.样例输出​​​​6.数据范围​​​​7.原题......
  • C++----二叉树的进阶
    文章目录​​前言​​​​一、二叉搜索树​​​​2.1二叉搜索树概念​​​​2.2二叉树节点​​​​2.3二叉搜索树操作​​​​1.二叉搜索树的查找​​​​2.二叉搜索树......
  • Node.js使用多进程提高任务执行效率的方法
    在Node.JS中使用多进程非常简单,合理使用多进程,可以解放硬件的能力,让软件的运行效率得到肉眼可见的提升。本文详细讲解了Node.js使用多进程提高任务执行效率的方法,对大家的学......
  • C++之字符串分割案例---数据分析(1)
    包含知识点:函数的使用、指针变量的使用、字符串查找、子字符串截取、字符串长度等。查看代码#include<iostream>#include<string>#include<cstdlib>usingnames......
  • bazel编译报错:absl/base/policy_checks.h:79:2: error: #error "C++ versions less th
      使用bazel编译一个软件时报错,报错的信息为:absl/base/policy_checks.h:79:2:error:#error"C++versionslessthanC++14arenotsupported." 整个的编译信息......
  • C++ 编程中常用的英文单词(首字母是G、H、I开头)
    学习编程不一定需要英语水平很高,能记住认识一些常用的英文单词也可以,有看不明白的文档资料也可以使用翻译工具,编写代码时大部分好用的IDE都是有代码提示的。本文主要介绍C+......
  • c++协程注意
    类客户{公:客户(){线=线程([本]{io环境_.跑();});}简单异步::协程::懒<极>异步连接(动主机,动端口){极中=协待工具:......
  • C++工程中的(.h文件)和(.cpp)文件如何管理
    整个工程的格式应该是这样的:#include"initiate_maze.hpp"voidinitiate_maze(intn,intm){srand(time(NULL));vector<string>things;stringa......
  • C++——指针
    一、指针的定义1int*p;2int*p;3int*p;4int*p;首先可以肯定的是上述四种写法(未初始化)都是可以的(本人推荐第一种,不因为什么,看着舒服!!!......