1.模板
/**** 可以发现**************************************************
* ①函数名相同,参数类型不同,模板函数可以与普通函数形成重载
* ②当自己以及实现函数功能时,优先调用:已实现普通函数(原因CPU推到需要花时间)
* ③调用有两种方式,自动类型推导 和 显示指定类型
* 注意:我们经常用 显示指定类型(减少CPU推到时间)
* ④模板的通用并不是万能的,在本案例中 数组就无法实现交换
* 解决方案:自己实现普通函数高阶
**************************************************************/
/********* 模板是动态绑定的: 也就是在调用时才产生 ******
* 程序规则自上而下,从左往右:
* 必须将模板放入同一文件
* **********************************************/
代码:
#include
using namespace std;
/**** 交换两个数据:定义myswap函数 ****/
void myswap(int &a,int &b) /*int 类型交换*/
{
int temp = a;
a = b;
b = temp;
cout << "void myswap(int &a,int &b)" << endl;
}
void myswap(char &a,char &b) /*char 类型交换*/
{
char temp = a;
a = b;
b = temp;
cout << "void myswap(char &a,char &b)" << endl;
}
/**** 使用模板技术 ****/
#include /* 打印类型信息 */
template /*建立 Type 虚拟万能类型 -> CPU自动推到 */
void myswap(Type &a,Type &b)
{
Type temp = a;
a = b;
b = temp;
cout << "\t类型名:" << typeid(Type).name()
<< "\t类型大小:" << sizeof(Type)
<< endl;
cout << "void myswap(Type &a,Type &b)" << endl;
}
/**** 可以发现**************************************************
* ①函数名相同,参数类型不同,模板函数可以与普通函数形成重载
* ②当自己以及实现函数功能时,优先调用:已实现普通函数(原因CPU推到需要花时间)
* ③调用有两种方式,自动类型推导 和 显示指定类型
* 注意:我们经常用 显示指定类型(减少CPU推到时间)
* ④模板的通用并不是万能的,在本案例中 数组就无法实现交换
* 解决方案:自己实现普通函数高阶
**************************************************************/
template /*建立 Type 虚拟万能类型 -> CPU自动推到 */
void myswap(Type a[],Type b[])
{
Type temp;
for(int i = 0; i < 5;i++)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
cout << "void myswap(int a[],int b[])" << endl;
}
class People
{
public: /* 双目运算符 , <<高阶 , >> , [] , () */
People(string name = "",int age = 0):m_name(name),m_age(age){} /*构造函数*/
/* 编译器默认提供 =运算符重载(浅) */
friend ostream &operator <<(ostream &out,const People &value)
{
out << "姓名:" << value.m_name << "\t年龄:" << value.m_age;
return out;
}
private:
string m_name;
int m_age;
};
int main()
{
{/**** int 类型交换 *****/
int a = 10,b = 20;
myswap(a,b); /* 自动类型推到 */
cout << "a = " << a << "\tb = " << b << endl;
}
{/**** char 类型交换 *****/
char a = 'A',b = 'B';
myswap(a,b); /* 自动类型推到 */
cout << "a = " << a << "\tb = " << b << endl;
}
{/**** double 类型交换 *****/
double a = 169.6,b = 157.4;
myswap(a,b); /* 指定显示类型调用 */
cout << "a = " << a << "\tb = " << b << endl;
}
{/**** People 类型交换 *****/
People a("师",18),b("老",19);
myswap(a,b);
cout << "a = " << a << "\tb = " << b << endl;
}
{/**** int 数组类型交换 *****/
int addr_a[5] = {1,2,3,4,5};
int addr_b[5] = {3,4,5,6,7};
myswap(addr_a,addr_b);
cout << "addr_a:";
for(int i = 0; i < 5;i++)
{
cout << addr_a[i] << ",";
}
cout << endl;
cout << "addr_b:";
for(int i = 0; i < 5;i++)
{
cout << addr_b[i] << ",";
}
cout << endl;
}
return 0;
}
2.
/******* 类模板 *******
* ①必须指定显示类型,在类名之后加<类型>
* ②模板注意事项:
* 1.程序自上而下,模板必须在同一文件
* 2.类模板:尽量所有实现都写在同一文件
* ******************/
代码:
list.h
#ifndef LIST_H
#define LIST_H
#include
using namespace std;
/* 定义类模板: */
template
class list
{
public:
list():m_max(100),m_size(0)
{
m_addr = new Type[m_max];
}
~list()
{
delete m_addr;
}
public:
Type &operator [](int index) /*[]运算符重载*/
{
return m_addr[index];
/*000000000000...*/
}
void push_back(Type value)
{
if(m_size+1 >= m_max) /*空间不够,重新申请新空间*/
{
Type *addr = new Type[m_max*2];
/**********拷贝老数据到新空间************/
memcpy(addr,m_addr,sizeof(Type)*m_max);
/**********释放老空间 ********/
delete m_addr;
/**********重新更改指向**********/
m_addr = addr;
/**********修改m_max******/
m_max *= 2;
}
m_addr[m_size] = value;
m_size++;
}
int size() const
{
return m_size;
}
void setSize(int size); /*类内.h声明,类.cpp实现*/
public: /* 单端动态数组 */
Type *m_addr;/*类型 数组名[个数];*/
int m_max; /*数组长度*/
int m_size; /*当前有效元素个数*/
};
#endif // LIST_H
mian.cpp
#include
#include "list.h" /*引入类模板*/
/****** 说过 #include 引入方式 *****
* 自己工作路径 : "头文件名" -> 先工作路径 -> 系统目录 -> 结束
* 系统库路径 : <头文件名> -> 直接系统目录 -> 结束
* ******************************/
using namespace std;
/******* 类模板 *******
* ①必须指定显示类型,在类名之后加<类型>
* ②模板注意事项:
* 1.程序自上而下,模板必须在同一文件
* 2.类模板:尽量所有实现都写在同一文件
* ******************/
int main()
{
/**** 案例:int 类型 ****/
list v; /*不知道用户要使用的类型吧?*/
/**** 使用自己的list *****/
v.push_back(10);
v.push_back(520);
//v.setSize(0); /*报错:不同文件实现,晚绑定失败*/
for(int i = 0; i < v.size();i++)
{
cout << v[i] << ",";
}
cout << endl;
return 0;
}
3.模板类继承
代码:
#include
using namespace std;
/**** 父类是类模板 ****/
template
class A
{
public:
Type m_value;
};
/**** B去继承于A类模板 ***/
class B : public A /**指定显示继承**/
{
public:
string m_name;
};
template
class C : public A
{
};
int main()
{
A v;
B b;
b.m_name = "李四";
C c;
c.m_value = "10.5";
cout << c.m_value << endl;
return 0;
}
4.STL 容器的使用 (vector)
/*********** vector 容器:单端数组 ************
* 头文件:#include
* 命名空间: using namemspace std
*
* 构造:vector()
* 析构:~vector()
* 尾插:push_back(Type Value)
* 尾删:pop_back()
* 清空:clear()
* 访问:
* at(int index)
* [](int index)
* front()
* back()
* 元素个数:size()
* 注意:在C++库中,一般类名和文件名相同,库一般不带.h
* *****************************************/
/*******************************************
* 单端数据初体验:
* ①插入数据 -> ②遍历数据内容{[]和at and for_each算法} ->算法需要用到算法库 #include
* push_back 了解迭代器知识
*
/***************** 迭代器 *****************************************************
* 通过基础知识,我们可以发现 vector是连续空间,所以迭代器是 随机访问迭代器
* 作用:用于算法和容器之间的胶合剂
* 定义迭代器变量:
* 容器类型<类型>::iterator 迭代器变量名;
* 使用迭代器:
* 针对于容器类型,能支持访问的都有
* iterator begin() Vs iterator end() ,可以发现都返回的是迭代子类型
* begin() : 首迭代子 -> 存放的是第一个元素的位置
* end() : 尾迭代子 -> 存放的是末尾之后的元素位置,所以没有数据,只是做标记
* 访问数据规则:可以将迭代子理解为指针,指针访问数据可以有两种方法: * 和 ->
* 随机访问迭代器规则: ++,--,[]
*
* template
* _Funct for_each(_IIter首迭代子, _IIter尾迭代子, _Funct仿函数策略)
* _Funct 原型 void func(Type value);
* **************************************************************************/
代码:
#include
/* ①引入头文件和命名空间 */
#include
/* ②引入通用算法库 */
#include
using namespace std;
/*********** vector 容器:单端数组 ************
* 头文件:#include
* 命名空间: using namemspace std
*
* 构造:vector()
* 析构:~vector()
* 尾插:push_back(Type Value)
* 尾删:pop_back()
* 清空:clear()
* 访问:
* at(int index)
* [](int index)
* front()
* back()
* 元素个数:size()
* 注意:在C++库中,一般类名和文件名相同,库一般不带.h
* *****************************************/
/*******************************************
* 单端数据初体验:
* ①插入数据 -> ②遍历数据内容{[]和at and for_each算法} ->算法需要用到算法库 #include
* push_back 了解迭代器知识
* ****************************************/
void test0()
{
/*1.创建 存放int类型的实例化对象*/
vector v;
/*2.插入数据: 10 , 20 , 50 */
v.push_back(10);
v.push_back(20);
v.push_back(50);
/*3.访问容器*/
cout << "当前元素个数:" << v.size() << endl;
cout << "front = " << v.front() << endl;
cout << "back = " << v.back() << endl;
#if 0
for(int i = 0; i < v.size();i++)
{
//cout << v[i] << ","; 是vector容器的 []运算符重载
cout << v.at(i) << ",";
}
cout << endl;
#else
/*for_each() 遍历算法 */
/***************** 迭代器 *****************************************************
* 通过基础知识,我们可以发现 vector是连续空间,所以迭代器是 随机访问迭代器
* 作用:用于算法和容器之间的胶合剂
* 定义迭代器变量:
* 容器类型<类型>::iterator 迭代器变量名;
* 使用迭代器:
* 针对于容器类型,能支持访问的都有
* iterator begin() Vs iterator end() ,可以发现都返回的是迭代子类型
* begin() : 首迭代子 -> 存放的是第一个元素的位置
* end() : 尾迭代子 -> 存放的是末尾之后的元素位置,所以没有数据,只是做标记
* 访问数据规则:可以将迭代子理解为指针,指针访问数据可以有两种方法: * 和 ->
* 随机访问迭代器规则: ++,--,[]
*
* template
* _Funct for_each(_IIter首迭代子, _IIter尾迭代子, _Funct仿函数策略)
* _Funct 原型 void func(Type value);
* **************************************************************************/
vector::iterator it;
cout << "*begin() = " << *v.begin() << endl;
cout << "*end() = " << *v.end() << endl;
cout << "*(--end()) = " << *(--v.end()) << endl;
for(it = v.begin() ; it != v.end() ;it++)
{
cout << *it << ",";
}
cout << endl;
class Print
{
public:
void operator ()(int value)
{
cout << value << ",";
}
};
for_each(v.begin(),v.end(),Print());
#endif
}
/********* 自己来实现以下 My_vector ************
* 本质:数组(动态)
* ******************************************/
template
class My_vector
{
public: /*** 迭代器 ****/
class iterator
{
public:
iterator(Type *ptr = NULL):Ptr(ptr){}
/*** 指针有访问操作: * 和 -> ***/
Type &operator *()
{
return *Ptr;
}
iterator &operator ++()
{
Ptr++;
return *this;
}
iterator operator ++(int)
{
iterator it(*this);
Ptr++;
return it;
}
private:
Type *Ptr;
};
public:
My_vector() /*配置器*/
:m_size(0),m_max(10)
{
/**** 申请空间 ****/
m_ptr = new Type[m_max];
}
~My_vector()
{
delete m_ptr;
}
void push_back(Type value)
{
if(m_size >= m_max)
{
/***** 申请空间 ******/
Type *ptr = new Type[m_max*2];
/***** 拷贝数据 ******/
memcpy(ptr,m_ptr,sizeof(Type)*m_max);
/***** 释放空间 ******/
delete m_ptr;
/***** 更改指向 ******/
m_ptr = ptr;
/***** 修改容量 ******/
m_max = m_max * 2;
}
m_ptr[m_size] = value;
m_size++;
}
Type &operator [](int index)
{
return m_ptr[index];
}
iterator begin() /*第一个元素的位置*/
{
return iterator(m_ptr);
}
protected:
Type *m_ptr; /*数组头*/
int m_size; /*元素个数*/
int m_max; /*容量*/
};
void test1()
{
My_vector v;
v.push_back(10);
v.push_back(20);
cout << *v.begin() << endl;
cout << *++v.begin() << endl;
}
/***** 存放自定义类型:Person ***************************
* 成员: 姓名 + 年龄
* 要注意数据结构中对自定义类型的支持:运算符重载实现
* ****************************************************/
class Person
{
public:
Person(string name = "",int age = 0):m_name(name),m_age(age){}
string m_name;
int m_age;
private:
friend ostream &operator <<(ostream &out,Person person)
{
out << person.m_name << "\t"
<< person.m_age;
return out;
}
};
#include
#include /*双端数组*/
#include /*链表*/
void test3()
{
/**** 1.实例化STL对象 ****/
vector v;
/**** 2.插入数据 ******/
v.push_back(Person("张三",17));
v.push_back(Person("李四",18));
/**** 3.输出数据 ******/
//cout << v[0] << endl;
//auto 自动类型推到 //iterator begin()
for(auto it = v.begin() ; it != v.end() ;it++)
{
cout << *it << endl;
}
}
/****** 人类分班 *********
*
*
*
* ********************/
void test4() /*容器嵌套*/
{
/*实例化年级容器*/
vector> v;
{/*一班*/
vector v1;
v1.push_back(Person("张三",18));
v1.push_back(Person("李四",17));
// vector::iterator it;
// for(it = v1.begin();it != v1.end() ;it++)
// {
// cout << *it << endl;
// }
v.push_back(v1);
}
{/*二班*/
vector v2;
v2.push_back(Person("李白",650));
v.push_back(v2);
}
/**** 遍历打印:年级 ****/
vector>::iterator it_i; /*定义迭代子*/
for(it_i = v.begin();it_i != v.end();it_i++) /*迭代子 *it_i => vector */
{
vector::iterator it_j;
cout << "班级信息:" << endl;
for(it_j = (*it_i).begin() ; it_j != (*it_i).end() ;it_j++)/* 迭代子 *it_j => Person */
{
cout << *it_j << endl;
}
}
}
int main()
{
//test0();
//test1();
test3();
//test4();
return 0;
}