数据结构与算法程序员C++

慕课网-C++远征之模板篇(下)-学习笔记

2017-09-01  本文已影响151人  天涯明月笙

C++远征之模板篇(下)

运算符重载

给原有的运算符赋予新功能

+ 数字相加。重载为字符串拼接

举个栗子:

int main()
{
    string str1("james");
    string str2("yuan");
    string str3 = str1 + "" + str2;
    cout << str3 <<endl;
    return 0; 
}

上述代码中= , +, <<都做了重载

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

关键字operator

一元运算符重载

一元运算符:只与一个操作数运算。

-(负号)的重载:

成员函数重载

class Coordinate
{
public:
    Coordinate(int x,int y);
    Coordinate& operator-();//

private:
    int m_iX;
    int m_iY;
}

//实现
//
Coordinate& Coordinate::operator-()
//隐藏的参数
{
    m_iX = -m_iX;
    m_iY = -m_iY;
    return *this;
}

使用时

int main()
{
    Coordinate coor1(3,5);

    -coor1; //coor1.operator-();

    return 0;
}

友元函数重载

class Coordinate
{
friend Coordinate& operator-(Coordinate &coor);
public:
    Coordinate(int x,int y);
    Coordinate& operator-();//

private:
    int m_iX;
    int m_iY;
}

//实现
//
Coordinate& operator-(Coordinate &coor)
{
    coor.m_iX = -coor.m_iX;
    coor.m_iY = -coor.m_iY;

    return *this;
}

//调用
//
int main()
{
    Coordinate coor1(3,5);

    -coor1; //operator-(cool);

    return 0;
}

成员函数重载与友元函数重载的区别。

  • operator-(cool):友元函数

++符号的重载:

++运算符前置重载

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);
    Coordinate operator++(int);//后置++
    //1. 返回的对象为对象。
    //2. 传入参数int。int没有任何用。只是为了标识。

private:
    int m_iX;
    int m_iY;
}


Coordinate operator++(int)
{
    Coordinate old(*this);
    m_iX++;
    m_iY++;

    return old;
}

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

    return 0;
}

一元运算符编码实现

运算符重载要求

成员函数重载:

#ifndef COORDINATE_H
#define COORDINATE_H
#include <iostream>
using namespace std;

class Coordinate
{
public:
    Coordinate(int x,int y);
    Coordinate & operator-();
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;

};
#endif


#include "Coordinate.h"

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
}

int Coordinate::getX()
{
    return m_iX;
}

int Coordinate::getY()
{
    return m_iY;
}
Coordinate &Coordinate::operator-()
{
    m_iX = -m_iX;
    this->m_iY = -this->m_iY;

    return *this;
}


#include "Coordinate.h"
#include <iostream>
#include <stdlib.h>
using namespace std;

int main()
{
    Coordinate coor1(1, 3);
    cout << coor1.getX() << "," << coor1.getY() << endl;
    -coor1; //coor1.operator-()
    cout << coor1.getX() << "," << coor1.getY() << endl;
    system("pause");
    return 0;
}

运行结果:
1,3

-1,-3

友元函数运算符重载

Coordinate.h:

class Coordinate
{
    friend Coordinate &operator-(Coordinate &c);

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

};

coordinate.cpp:

#include "Coordinate.h"

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
}

int Coordinate::getX()
{
    return m_iX;
}

int Coordinate::getY()
{
    return m_iY;
}
Coordinate &operator-(Coordinate &c)
{
    c.m_iX = -c.m_iX;
    c.m_iY = -c.m_iY;

    return c;
}

main.cpp:没有变化

运行结果也没有变化。

编码实现二

#ifndef COORDINATE_H
#define COORDINATE_H
#include <iostream>
using namespace std;

class Coordinate
{
    friend Coordinate &operator-(Coordinate &c);

public:
    Coordinate(int x,int y);
    Coordinate &operator++();//前置++
    Coordinate operator++(int);//后置++

    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;

};
#endif


#include "Coordinate.h"

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
}

int Coordinate::getX()
{
    return m_iX;
}

int Coordinate::getY()
{
    return m_iY;
}
Coordinate &operator-(Coordinate &c)
{
    c.m_iX = -c.m_iX;
    c.m_iY = -c.m_iY;

    return c;
}
Coordinate &Coordinate::operator++()
{
    m_iX++;
    m_iY++;
    return *this;
}
Coordinate Coordinate::operator++(int)
{
    Coordinate old(*this);
    this->m_iX++;
    this->m_iY++;
    return old;
}


#include "Coordinate.h"
#include <iostream>
#include <stdlib.h>
using namespace std;

int main()
{
    Coordinate coor1(1, 3);
    cout << coor1.getX() << "," << coor1.getY() << endl;
    ++coor1;
    cout << coor1.getX() << "," << coor1.getY() << endl;
    -coor1; //coor1.operator-()
    cout << coor1.getX() << "," << coor1.getY() << endl;
    cout << (coor1++).getX() << ",";
    cout << (coor1++).getY() << endl;
    cout << coor1.getX() << "," << coor1.getY() << endl;
    //上面两个分号所以coor1++执行了两次。
    //到上一行打印的时候已经是x,y都加了2了。
    system("pause");
    return 0;
}
运行结果

二元运算符重载

+成员函数重载

class Coordinate
{
public:
    Coordinate(int x,int y);
    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 coor1(4,7);
    Coordinate coor1(0,0);

    coor3 = coor1 + coor2; 
    //operator+(coor1,coor2)
    //
    return 0; 
}

<<输出运算符

class Coordinate
{
    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)
{
    out << coor.m_iX <<","<<coor.m_iY;

    return out;
}

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

    return 0;
}

理解到cout是一个ostream的对象。

输出运算符可以采用成员函数重载?

[]索引运算符

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;
}

索引运算符可以采用友元函数重载?

不能采用友元函数重载。友元函数第一个参数可以是this指针,也可以是其他东西。只有this指针才能指向对象。

二元运算符代码示例

要求

运算符的重载:

#ifndef COORDINATE_H
#define COORDINATE_H
#include <iostream>//包含了ostream
using namespace std;

class Coordinate
{
    friend Coordinate &operator-(Coordinate &c);
    friend Coordinate operator+(Coordinate c1,Coordinate c2);
    friend ostream &operator<<(ostream &output, Coordinate &coor);
public:
    Coordinate(int x,int y);
    Coordinate &operator++();//前置++
    Coordinate operator++(int);//后置++
    //Coordinate operator+(Coordinate &c);
    //其实里面有两个参数。
    int operator [](int index);
    int getX();
    int getY();
private:
    int m_iX;
    int m_iY;

};
#endif

#include "Coordinate.h"

Coordinate::Coordinate(int x, int y)
{
    m_iX = x;
    m_iY = y;
}

int Coordinate::getX()
{
    return m_iX;
}

int Coordinate::getY()
{
    return m_iY;
}
Coordinate &operator-(Coordinate &c)
{
    c.m_iX = -c.m_iX;
    c.m_iY = -c.m_iY;

    return c;
}
Coordinate &Coordinate::operator++()
{
    m_iX++;
    m_iY++;
    return *this;
}
Coordinate Coordinate::operator++(int)
{
    Coordinate old(*this);
    this->m_iX++;
    this->m_iY++;
    return old;
}

//Coordinate Coordinate::operator+(Coordinate &c)
//{
//  Coordinate temp(0, 0);
//  temp.m_iX = this->m_iX +c.m_iX;
//  temp.m_iY = this->m_iY +c.m_iY;
//
//  return temp;
//}
Coordinate operator+(Coordinate c1, Coordinate c2)
{
    Coordinate temp(0, 0);
    temp.m_iX = c1.m_iX + c2.m_iX;
    temp.m_iY = c1.m_iY + c2.m_iY;

    return temp;
}

ostream &operator<<(ostream &output, Coordinate &coor)
{
    output << coor.m_iX << "," << coor.m_iY;
    return output;
}
int Coordinate::operator [](int index)
{
    if (0 == index)
    {
        return m_iX;
    }if (1 == index)
    {
        return m_iY;
    }
}

#include "Coordinate.h"
#include <iostream>
#include <stdlib.h>
using namespace std;

int main()
{
    Coordinate coor1(1, 3);
    Coordinate coor2(2, 4);
    Coordinate coor3(0, 0);

    coor3 = coor1 + coor2;

    //cout << coor3.getX() << "," << coor3.getY() << endl;

    cout << coor3[0] <<endl;
    cout << coor3[1] << endl;
    

    system("pause");
    return 0;
}

单元巩固

定义Coordinate类
数据成员:m_iX, m_iY
成员函数:构造函数
重载“--”运算符,重载“+”运算符

#include <iostream>
using namespace std;

/**
 * 定义Coordinate类
 * 数据成员:m_iX,m_iY
 * 成员函数:构造函数
 * 重载--运算符,重载+运算符
 */
class Coordinate
{
public:
    Coordinate(int x, int y)
    {
        m_iX = x;
        m_iY = y;
    }
    // 前置--运算符重载
    Coordinate & operator--()
    {
        this ->m_iX--;
        this ->m_iY--;
        return *this;
    }
    
    
    // 后置--运算符重载
    Coordinate operator--(int)
    {
        Coordinate old = *this;
        this ->m_iX--;
        this ->m_iY--;
        return old;
    }
    
    
    
    // +号运算符重载
    Coordinate &operator+(Coordinate c)
    {
        Coordinate temp(0,0);
        temp.m_iX = this ->m_iX + c.m_iX;
        temp.m_iY = this ->m_iY + c.m_iY;
        return temp;
    }
    
    

public:
    int m_iX;
    int m_iY;
};

int main(void)
{
    Coordinate coor1(1, 3);
    Coordinate coor2(2, 4);
    Coordinate coor3(0, 0);

    coor1--;
    --coor2;
    coor3 = coor1 + coor2;

    cout << coor3.m_iX << endl;
    cout << coor3.m_iY << endl;

    return 0;
}

运行结果:1 5

函数模板

为什么要使用模板?

int max(int a,int b)
{
    return (a>b)?a:b;
}
float max(float a,float b)
{
    return (a>b)?a:b;
}
char max(char a,char b)
{
    return (a>b)?a:b;
}

三种不同类型,但是运算逻辑完全一致。

解决方案:
类型作为参数传入。计算机来做出这三个函数。

关键字:template typename class

这里的class不是类。是来表面数据类型的。

template <class T>
//声明一种参数类型
T max(T a,T b)     //函数模板
{
    return (a>b)?a:b;
}

int ival = max(100,99); //模板函数
//不写明,计算机会自动进行识别。
char cval = max<char>('A','B');
//指定之后,传入参数一定要是这种数据类型才可以

函数模板是模子,生产出来的是模板函数。
只有函数模板,计算机不会产生代码数据。只有使用时才会产生真正的代码

template <typename T>
void swap(T& a,T& b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

int x =20,y=30;
swap<int>(x,y);

变量作为模板参数

template <int size>
void display()
{
    cout << size <<endl;
}

display<10>();

多参数函数模板

template <typename T,typename C>
void display(T a,C b)
{
    cout << a <<" " <<b <<endl;
}

//使用
int a = 1024; string str = "helloworld";
display<int ,string>(a,str);

typename 和class可以混用

template <typename T,class U>
T minus(T* a, U b)

template <typename T,int size>
void display(T a)
{
    for(int i=0;i < size;i++)
    cout << a << endl;
}

display<int,5>(15);

函数模板与重载

函数模板可以做出无数个模板函数来。

模板函数之间形成重载。

不同的函数模板做出来的模板函数也能形成重载

template <typename T>
void display(T a);

template <typename T>
void display(T a,T b);//参数个数不同

template <typename T,int size>
void display(T a);

display<int>(10);
display<int>(10,20);
display<int,5>(30);//三个函数形成重载

函数模板代码实践

要求
#include <iostream>
#include <stdlib.h>
using namespace std;

template <typename T>

void display(T a)
{
    cout << a << endl;
}

template <typename T, class S>
void display(T t,S s)
{
    cout << t << endl;
    cout << s << endl;
}

template <typename T,int Ksize>
//该变量实例化时变为常量

void display(T a)
{
    for (int i = 0; i < Ksize; i++)
    {
        cout << a << endl;
    }
}

int main()
{
    display<int>(10);
    display<double>(10.98);
    display<int,double>(5, 8.3);
    display<int,3>(10);
    system("pause");
    return 0;
}
运行结果

单元巩固

定义一个函数模板,功能是交换两个数的位置

#include <iostream>
using namespace std;

/**
 * 定义模板函数swapNum
 * 实现功能:交换两个数的位置
 */
template <typename T>
void swapNum(T &a,T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

int main(void)
{
    int x = 10;
    int y = 20;
    // 调用模板函数
    swapNum(x,y);
        cout << "x = " << x << endl;
        cout << "y = " << y << endl;
    return 0;
}

运行结果:
x = 20 y = 10

类模板

template <class T>
class MyArray
{
public:
    void display()
    {...}
private:
    T *m_pArr;
}

只有数据类型不同,其他基本都相同。

类外定义成员函数:

template <class T>
void MyArray<T>::display()
{

}

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

    return 0;
}

类模板

模板类多个参数的使用情况

template <template T,int KSize>
class Container
{
public:
    void display();
private:
    T m_obj;
}

//
template<typename T,int KSize>
void Container<T,KSize>::display()
{
    for (int i = 0; i < KSize; ++i)
    {
        cout << m_obj << endl;
    }
}

int main()
{
    Container<int,10> ct1;
    ct1.display();

    return 0;
}

包含多个参数的类模板(类外定义),每一个成员函数前都要写上template代码。

类模板编码实现

要求

myarry.h:

#ifndef MYARRAY_H
#define MYARRAY_H

#include <iostream>
using namespace std;

template <typename T,int Ksize,int KVal>//模板参数列表
class MyArray
{
public:
    MyArray();
    ~MyArray()
    {
        delete[]m_pArr;
        m_pArr = NULL;
    }//写在类内部的函数不需要注意什么。
    void display();

private:
    T *m_pArr;
};
template <typename T, int KSize, int KVal>
MyArray<T, KSize, KVal>::MyArray()
{
    m_pArr = new T[KSize];
    for (int i = 0; i < KSize; i++)
    {
        m_pArr[i] = KVal;
    }
}

template <typename T,int KSize,int KVal>
void MyArray<T, KSize, KVal>::display()
{
    for (int i = 0; i < KSize; i++)
    {
        cout << m_pArr[i] << endl;
    }
}

#endif

myarry.cpp:

//什么都不写

main.cpp:

#include <stdlib.h>
#include <string>
#include "MyArray.h"
using namespace std;

int main()
{
    MyArray<int, 5, 6> arr;//已经形成模板类了
    arr.display();
    system("pause");
    return 0;
}

运行结果:

5个6
  • 定义一个类模板就相当于定义了一系列功能相同类型不同的类

单元巩固

定义一个矩形类模板
该模板中含有计算矩形面积和周长的成员函数
数据成员为矩形的长和宽。

#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;
    cout << rect.calePerimeter() << endl;
    return 0;
}

注意事项:

template <typename T>
Rect<T>::Rect(T length,T height)//《》加在类上而不是方法。

标准模板库

STL: standard template Lib

标准模板库就是系统已经预先写好了的一些模板的集合,你可以直接使用(将之实例化)

常用部分:

向量

本质:数组的封装。根据存储的元素个数自动变长或缩短。
特点:随机读取能在常数时间内完成

向量的初始化方法

分别是:

具体使用:

vector<int> ivec1;
vector<int> ivec2(ivec1);

vector<string> svec1;
vector<string> svec2(svec1);

vector<int> ivec4(10,-1);//数组中包含10个-1
vector<string> ivec4(10,"hi");//数组中包含10个hi

向量初始化之后必须要有配套的函数才能让我们体会到方便

配套的函数
int main()
{
    vector<int> vec;
    vec.push_back(10);//最尾部插入元素10
    vec.push_pop();//删除10
    cout << vec.size()<<endl;//此时仍然为0
    return 0;
}

for(int k=0;k < vec.size();k++)
{
    cout << vec[k] << endl;
}

迭代器(iterator)遍历。

int main()
{
    vector vec;
    vec.push_back("hello");
    vector<string>::iterator citer = vec.begin();
    //<>标明向量使用的数据类型。::标识出当前迭代器是属于向量的迭代器
    //迭代器的变量名citer 数据类型:`vector<string>::iterator citer`
    //通过该迭代器指向当前向量的第一个元素。
    for (;citer != vec.end();citer++)
    //中止条件:end指当前向量vec最后一个向量的下一个位置。
    //指向下一个元素。
    {
        cout << *citer << endl;
    }

}

list:链表

链表

双链表:可以从头找到尾,也可以从尾找到头。

d 和 e中间插入数据,让d指向新数据,新数据指向e就可以了。

特点:数据插入速度快
使用方法上与数组基本相同。

map:映射

map映射

键值映射一一对应。通过键找值

map<int,string> m;//通过映射定义一个映射对象
pair<int,string> p1(10,"shanghai");//向映射中放入key&value
pair<int,string> p2(20,"beijing");
m.insert(p1);//将pair放入m中
m.insert(p2);
cout << m[10] << endl;//通过key访问值
cout << m[20] << endl;


map<string,string> m;//通过映射定义一个映射对象
pair<string,string> p1("S","shanghai");//向映射中放入key&value
pair<string,string> p2("B","beijing");
m.insert(p1);//将pair放入m中
m.insert(p2);
cout << m["S"] << endl;//通过key访问值
cout << m["B"] << endl;

标准模板库代码实现

标准模板库
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;

int main()
{
    vector<int> vec;
    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(6);//从尾部去插入
    /*vec.pop_back();

    cout << vec.size() << endl;*/

    /*for (int i=0;i<vec.size();i++)
    {
        cout << vec[i] << endl;
    }
*/
    //迭代器
    vector<int>::iterator itor = vec.begin();
    //cout << *itor << endl;
    for (;itor != vec.end();itor++)
    {
        cout << *itor << endl;
    }
    cout << vec.front() << endl;//第一个元素
    cout << vec.back() << endl;//最后一个元素

    system("pause");
    return 0;
}

list的遍历代码:

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
using namespace std;

int main()
{
    list<int> list1;
    list1.push_back(4);
    list1.push_back(7);
    list1.push_back(10);

    //for (int i=0;i<list1.size();i++)
    //{
    //  cout << list1[i] << endl;//错误

    //}
    list<int>::iterator itor = list1.begin();
    for (;itor != list1.end();itor++)
    {
        cout << *itor << endl;
    }
    system("pause");
    return 0;
}

map遍历

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
#include <string>
using namespace std;

int main()
{
    map<int,string> m;
    pair<int,string> p1(3,"hello");
    pair<int,string> p2(6,"world");
    //m.push_back(p1);//错误
    m.insert(p1);
    m.insert(p2);

    cout << m[3] << endl;
    cout << m[6] << endl;

    map<int,string>::iterator itor = m.begin();
    for (;itor != m.end();itor++)
    {
        //cout << *itor << endl;//错误,每个都包含keyvalue
        cout << itor->first << endl;
        cout << itor->second << endl;
    }

    system("pause");
    return 0;
}

string类型map

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
#include <string>
using namespace std;

int main()
{
    map<string,string> m;
    pair<string,string> p1("H","hello");
    pair<string,string> p2("W","world");
    //m.push_back(p1);//错误
    m.insert(p1);
    m.insert(p2);

    cout << m["H"] << endl;
    cout << m["W"] << endl;

    map<string,string>::iterator itor = m.begin();
    for (;itor != m.end();itor++)
    {
        //cout << *itor << endl;//错误,每个都包含keyvalue
        cout << itor->first << endl;
        cout << itor->second << endl;
    }

    system("pause");
    return 0;
}

单元巩固

使用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 itor1 = vec.begin();
    for(;itor1 != vec.end();itor1++)
    {
        cout << *itor1 <<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 itor2 = m.begin();
    for(;itor2 != m.end();itor2++)
    {
        cout << itor2->first <<endl;
        cout << itor2->second <<endl;
    }
    return 0;
}

运行结果:

运行结果

注意事项:

 cout << itor2->first <<endl;
 cout << itor2->second <<endl;

itor1和itor2不能重名

上一篇下一篇

猜你喜欢

热点阅读