c++(四)
- 运算符重载
- 可重载的运算符
- 不可重载的运算符
- 运算符重载的格式
- 运算符重载的方式
- 友元函数进行运算符重载
- 成员函数进行运算符重载
- 模板
- 定义的格式
- 函数模板
- 类模板
- 标准模板库
- vector向量容器
- STL中的list
- map向量容器
运算符重载
运算符相似,运算符相同,操作数不同,与返回值无关的一组函数
目的:让参与运算的数据类型更多样化—>c++可拓展性的体现
可重载的运算符
不可重载的运算符
运算符重载的格式
运算符重载的方式
友元函数进行运算符重载
案例1:复数 a+bi
#include <iostream>
using namespace std;
class CComplex
{
public:
CComplex(int rear = 2, int img = 3) :rear(rear), img(img)
{
cout << "CComplex(int,int)" << endl;
}
~CComplex()
{
cout << "~CComplex()" << endl;
cout << this << endl;
}
void show()
{
cout << this->rear << "+" << this->img << "*i" << endl;
}
friend CComplex operator+(CComplex& obj1, CComplex& obj2);
private:
int rear;//实部
int img;//虚部
};
CComplex operator+(CComplex& obj1, CComplex& obj2)
{
CComplex obj3;
cout << &obj3 << endl;
obj3.rear = obj1.rear + obj2.rear;
obj3.img = obj1.img + obj2.img;
return obj3;
}
int main()
{
CComplex c1(1,2);
cout << &c1 << endl;
CComplex c2(2,3);
cout << &c2 << endl;
//Complex c3 = c1 + c2;//隐式调用
CComplex c3 = operator+(c1, c2);//显示调用
cout << &c3 << endl;
c3.show();
return 0;
}
案例2:重载前置++
#include <iostream>
using namespace std;
//使用友元函数实现++符号的自增
class CComplex
{
public:
CComplex(int rear = 1, int img = 1);
~CComplex();
void show();
friend void operator++ (CComplex& demo);
private:
int rear;
int img;
};
CComplex::CComplex(int rear, int img)
{
this->rear = rear;
this->img = img;
cout << "构造" << endl;
}
CComplex::~CComplex()
{
cout << "析构" << endl;
}
void CComplex::show()
{
cout << this->rear << "+" << this->img << "*i" << endl;
}
void operator++ (CComplex& demo)
{
++demo.rear;
++demo.img;
}
int main()
{
CComplex c1(2,3);
//++c1;//隐式调用
operator++(c1);
c1.show();
}
成员函数进行运算符重载
案例1:重载前置++,后置++
#include <iostream>
using namespace std;
//使用成员函数实现++符号的自增,后++
class CComplex
{
public:
CComplex(int rear = 1, int img = 1);
~CComplex();
void show();
CComplex& operator++ ();
CComplex& operator++(int n);
private:
int rear;
int img;
};
CComplex::CComplex(int rear, int img)
{
this->rear = rear;
this->img = img;
cout << "构造" << endl;
}
CComplex::~CComplex()
{
cout << "析构" << endl;
}
void CComplex::show()
{
cout << this->rear << "+" << this->img << "*i" << endl;
}
CComplex& CComplex::operator++ ()
{
++this->rear;
++this->img;
return *this;
}
CComplex& CComplex::operator++(int n)
{
CComplex temp = *this;
this->rear++;
this->img++;
return temp;
}
int main()
{
CComplex c1(2, 3);
//++c1;//隐式调用
c1.operator++();//显示调用
c1.show();
CComplex c2(3, 4);
c2.operator++(1).show();
c2.show();
}
总结:
<1>友元重载参数要比成员重载的参数多一个,因为成员函数默认有一个this指针
<2>并不是所有的运算符都可以通过友元或者成员重载
cin >> 变量;//只能通过友元函数进行重载
#include <iostream>
using namespace std;
//重载cin,实现可以输入对象
class CComplex
{
private:
int rear;
int img;
public:
void show();
friend CComplex& operator >> (istream& tmp, CComplex& c1);
protected:
};
void CComplex::show()
{
cout << this->rear << "+" << this->img << "*i" << endl;
}
CComplex& operator>>(istream& tmp, CComplex& c1)
{
cout << "rear:" << endl;
tmp >> c1.rear;
cout << "img:" << endl;
tmp >> c1.img;
return c1;
}
int main()
{
CComplex c1;
cin >> c1;
c1.show();
}
模板
- 模板是支持参数化多态的工具,就是让类或者函数声明为一种通用类型,使得类中的某些数据成员或者成员函数的参数、返回值在实际使用时可以是任意类型
- 减少代码冗余,提高开发效率
定义的格式
template<class/typename T>
返回值类型 函数名(参数列表)
{
;
}
函数模板
- 函数模板是真正的函数吗?不是
- 什么时候才能变成真正的函数呢?
#include <iostream>
using namespace std;
template<typename T>
T MAX(T a, T b) //不占内存空间
{
return a > b ? a : b;
}
int main()
{
//实例化模板
cout << MAX<int>(1, 2) << endl;
cout << MAX<string>("hello", "c++");
cout << MAX<int>(3, 4) << endl;//类型相同的模板函数只会生成一次
return 0;
}
总结:
<1>调用函数时,将模板的数据类型具体化的时候,才会变成真正的函数,此时占内存空间,称为模板
函数
<2>类型相同的模板函数只会生成一次
<3>函数模板可以重载
案例:用模板实现数组的输出
#include <iostream>
using namespace std;
//模板实现数组的输出
template<typename T>
void output(T arr[],int n)
{
int i;
for (i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int length = sizeof(arr) / sizeof(int);
output<int>(arr, length);
string brr[] = { "hello", "c++" };
length = sizeof(brr) / sizeof(string);
output<string>(brr, length);
char crr[] = { 'a', 'b', 'c'};
length = sizeof(crr) / sizeof(char);
output<char>(crr, length);
return 0;
}
类模板
实现:链表:带头节点的单向不循环列表
<1>节点类(数据域、指针域)
<2>链表的类(增(尾插法)、删、改、查)、头结点
#include <iostream>
using namespace std;
//结点
class linkNode
{
public:
int data;
linkNode* next;
//构造
linkNode();
//析构
~linkNode();
protected:
};
//操作
class Handle
{
private:
linkNode* head;
public:
//构造
Handle();
//析构
~Handle();
//插入(尾插)
void insert(int data);
//查
void search();
protected:
};
linkNode::linkNode()
{
this->data = 0;
this->next = nullptr;
cout << "构造" << endl;
}
linkNode::~linkNode()
{
cout << "析构" << endl;
}
Handle::Handle()
{
this->head = new linkNode;
}
Handle::~Handle()
{
}
void Handle::insert(int data)
{
//创建一个新结点
linkNode* pNew = new linkNode;
//赋值
pNew->data = data;
//找尾结点
linkNode* pFind = this->head;
while (pFind->next != nullptr)
{
pFind = pFind->next;
}
//插入
pFind->next = pNew;
}
void Handle::search()
{
linkNode* pFind = this->head->next;
if (pFind == nullptr)
{
return;
}
while (pFind != nullptr)
{
cout << pFind->data << " ";
pFind = pFind->next;
}
cout << endl;
}
int main()
{
Handle han;
han.insert(10);
han.insert(20);
han.insert(30);
han.search();
return 0;
}
类模板:
#include <iostream>
using namespace std;
template <typename T>
//结点
class linkNode
{
public:
T data;
linkNode<T>* next;
//构造
linkNode();
//析构
~linkNode();
protected:
};
//操作
template <typename T>
class Handle
{
private:
linkNode<T>* head;
public:
//构造
Handle();
//析构
~Handle();
//插入(尾插)
void insert(T data);
//查
void search();
protected:
};
template <typename T>
linkNode<T>::linkNode()
{
//this->data = 0;
this->next = nullptr;
cout << "构造" << endl;
}
template <typename T>
linkNode<T>::~linkNode()
{
cout << "析构" << endl;
}
template <typename T>
Handle<T>::Handle()
{
this->head = new linkNode<T>;
}
template <typename T>
Handle<T>::~Handle()
{
}
template <typename T>
void Handle<T>::insert(T data)
{
//创建一个新结点
linkNode<T>* pNew = new linkNode<T>;
//赋值
pNew->data = data;
//找尾结点
linkNode<T>* pFind = this->head;
while (pFind->next != nullptr)
{
pFind = pFind->next;
}
//插入
pFind->next = pNew;
}
template <typename T>
void Handle<T>::search()
{
linkNode<T>* pFind = this->head->next;
if (pFind == nullptr)
{
return;
}
while (pFind != nullptr)
{
cout << pFind->data << " ";
pFind = pFind->next;
}
cout << endl;
}
int main()
{
Handle<int> han;
han.insert(10);
han.insert(20);
han.insert(30);
han.search();
Handle<string> han2;
han2.insert("hello");
han2.insert("c++");
han2.search();
return 0;
}
总结:
<1>类模板中使用一个或多个虚拟类型作为其成员数据类型的时候
<2>类模板不能分文件实现
标准模板库
即标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和DavidR Musser在惠普实验室工作时所开发出来的。STL主要是一些“容器”的集合,这些“容器”有list、vector、set、map,等等,STL也是算法和其他一些组件的集合,是世界上顶级C++程序员多年的杰作,是泛型编程的一个经典范例。
STL可分为六个部分:
容器(containers)
迭代器(iterators)
空间配置器(allocator)
配接器(adapters)
算法(algorithms)
仿函数(functors)
容器(containers)//类模板
特殊的数据结构,实现了数组、链表、队列、等等,实质是模板类
迭代器(iterators)//对象指针
一种复杂的指针,可以通过其读写容器中的对象,实质是运算符重载
算法(algorithms)//对象的操作
读写容器对象的逻辑算法:排序、遍历、查找、等等,实质是模板函数
空间配置器(allocator)
容器的空间配置管理的模板类
配接器(adapters)
用来修饰容器、仿函数、迭代器接口
仿函数(functors)
类似函数,通过重载()运算符来模拟函数行为的类
组件间的关系
container(容器) 通过 allocator(配置器) 取得数据储存空间,algorithm(算法)通过iterator(迭代器)存取 container(容器) 内容,functor(仿函数) 可以协助 algorithm(算法) 完成不同的策略变化,adapter(配接器) 可以修饰或套接 functor(仿函数)
vector向量容器
底层实现:数组
特点:<1>地址连续
<2>a、通过索引的方式去访问 b、通过迭代器访问
<3>访问方便
<4>插入、删除需要移动元素,不方便
<5>大小不固定
本质:vector是对数组的封装
#include <iostream>
#include <vector>
using namespace std;
/*
* 类似于数组
* 地址连续,可以使用索引访问,也可以使用迭代器访问,查询方便,增加和删除不方便,大小不固定
*/
int main()
{
//实例化vector类模板
vector<string> list_vect;
//增加元素
//void push_back(const T& x)在容器的末尾插入一个元素
list_vect.push_back("hello");
list_vect.push_back("world");
list_vect.push_back("c++");
//访问
//使用索引方式
//size_type size() const;用来返回容器中元素个数
for (int i = 0; i < list_vect.size(); i++)
{
//const_reference at ( size_type n ) const;获取容器某个位置上的元素值
cout << list_vect.at(i) << " ";
}
cout << endl;
//使用迭代器访问
vector<string>::iterator it;
//获取第二个位置的iterator
it = ++list_vect.begin();
//在某位置上增加元素
list_vect.insert(it, "hahaha");
//iterator begin()返回第一个元素的迭代器
//iterator end()返回最后一个元素的下一个位置的迭代器
for (it = list_vect.begin(); it < list_vect.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//删除某一位置上的元素
//获取第二个位置的iterator
it = ++list_vect.begin();
list_vect.erase(it);
for (it = list_vect.begin(); it < list_vect.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//修改第二个位置的值
/*it = ++list_vect.begin();
list_vect.erase(it);
it = ++list_vect.begin();
list_vect.insert(it, "hahaha");*/
list_vect.at(1) = "hahaha";
for (it = list_vect.begin(); it < list_vect.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
STL中的list
底层结构:双向链表
特点:
<1>内存中的地址是不连续–>不能通过索引的方式去访问–>访问效率没有vector高
<2>频繁的插入、删除不需要移动元素,效率比vector
#include <iostream>
#include <list>
using namespace std;
class Stu
{
public:
Stu(int sno = 1, string name = "张三") :sno(sno), name(name)
{
cout << "构造" << endl;
}
~Stu()
{
cout << "析构" << endl;
}
void show()
{
cout << "学号:" << this->sno << ",姓名:" << this->name << endl;
}
private:
int sno;
string name;
protected:
};
void showList(list<Stu>& list_s)
{
list<Stu>::iterator it;
for (it = list_s.begin(); it != list_s.end(); it++)
{
it->show();
}
}
int main()
{
//实例化类模板
list<Stu> list_s;
//插入
//void push_back ( const T& x );在列表的末尾插入一个元素
list_s.push_back(Stu());
//void push_front ( const T& x );在列表的头部插入一个元素
list_s.push_front(Stu(2, "李四"));
//iterator insert ( iterator position, const T& x ); 在列表的指定位置插入一个元素
list<Stu>::iterator it;
it = ++list_s.begin();//获取第二个位置
list_s.insert(it, Stu(3, "王五"));
//查看,只能以迭代器的方式
/*for (it = list_s.begin(); it != list_s.end(); it++)
{
it->show();
}*/
showList(list_s);
//删除
//iterator erase ( iterator position );删除某个位置的元素
//it = ++list_s.begin();//获取第二个位置
it = list_s.begin();
advance(it, 1);
list_s.erase(it);
//查看,只能以迭代器的方式
/*for (it = list_s.begin(); it != list_s.end(); it++)
{
it->show();
}*/
showList(list_s);
//修改
it = ++list_s.begin();//获取第二个位置
list_s.erase(it);
it = ++list_s.begin();//获取第二个位置
list_s.insert(it, Stu(3, "王五"));
//查看,只能以迭代器的方式
/*for (it = list_s.begin(); it != list_s.end(); it++)
{
it->show();
}*/
showList(list_s);
return 0;
}
map向量容器
底层结构:红黑树—>二叉树的一种
以键值对的形式存储
key—>value,key值是唯一的
特点:
<1>查找的速度特别快
<2>自动按照从小到大的顺序去排序
应用场景:频繁的查找
#include <iostream>
#include <map>
using namespace std;
class Stu
{
public:
Stu(int sno = 1, string name = "张三") :sno(sno), name(name)
{
cout << "构造" << endl;
}
~Stu()
{
cout << "析构" << endl;
}
void show()
{
cout << "学号:" << this->sno << ",姓名:" << this->name << endl;
}
void setname(string name)
{
this->name = name;
}
private:
int sno;
string name;
protected:
};
void showList(map<int, Stu*> mymap)
{
map<int, Stu*>::iterator it;
for (it = mymap.begin(); it != mymap.end(); it++)
{
cout << "key:" << it->first << " ";
it->second->show();
}
cout << endl;
}
int main()
{
//实例化类模板
map<int, Stu*> mymap;
map<int, Stu*>::iterator it;
//插入
Stu stu1;
mymap.insert(pair<int, Stu*>(2, &stu1));
it = mymap.begin();
Stu stu2(2, "王五");
mymap.insert(it, pair<int, Stu*>(1, &stu2));
Stu stu3(3, "李四");
mymap.insert(pair<int, Stu*>(3, &stu3));
showList(mymap);
//删除
mymap.erase(2);
showList(mymap);
//修改
it = mymap.find(1);
if (it != mymap.end())
{
(*it).second->setname("刘六");
}
showList(mymap);
return 0;
}