10-C++远征之模板篇-学习笔记

作者: 天涯明月笙 | 来源:发表于2018-07-24 17:04 被阅读19次

C++远征之模板篇

将会学到的内容:

  • 模板函数 & 模板类 -> 标准模板类
  • 友元函数 & 友元类
  • 静态数据成员 & 静态成员函数
  • 运算符重载: 一切皆有可能

友元函数

函数定义分类:

1. 全局函数
2. 成员函数

友元全局函数

例子:

class Coordinate
{
    friend void printXY(Coordinate &c);
public:
    Coordinate(int x,int y);
private:
    int m_iX;
    int m_iY;
}

关键字friend + 声明友元函数(对象的引用或指针)

  • 传入引用或指针访问速度更快,不提倡直接传入对象。
要求

友元全局函数

2-2-FriendFunctionGlobal

Time.h

#ifndef TIME_H
#define TIME_H

#include <iostream>
using namespace std;

class Time
{
    friend void printTime(Time &t);//重点
public:
    Time(int hour,int min,int sec);

private:
    int m_iHour;
    int m_iMinute;
    int m_iSecond;

};
#endif

Time.cpp

#include "Time.h"

Time::Time(int hour, int min, int sec)
{
    m_iHour = hour;
    m_iMinute = min;
    m_iSecond = sec;
}

main.cpp

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

void printTime(Time &t);
int main()
{
    Time t(6, 34, 35);
    printTime(t);
    system("pause");
    return 0;
}

void printTime(Time &t)
{
    cout << t.m_iHour << endl;
    // Time::m_iHour”: 无法访问 private 成员(在“Time”类中声明)
    cout << t.m_iMinute << endl;
    cout << t.m_iSecond << endl;
}
要求

2-5-FriendClass

Time.h

#ifndef TIME_H
#define TIME_H

class Match;//
class Time
{
    friend Match;// 声明自己友元
public:
    Time(int hour,int min,int sec);

private:
    void printTime();
    int m_iHour;
    int m_iMinute;
    int m_iSecond;

};
#endif

Time.cpp

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

Time::Time(int hour, int min, int sec)
{
    m_iHour = hour;
    m_iMinute = min;
    m_iSecond = sec;
}
void Time::printTime()
{
    cout << m_iHour << "时" << m_iMinute << "分" << "秒" << endl;
}

Match.h

#ifndef MATCH_H
#define MATCH_H

#include "Time.h"

class Match
{
public:
    Match(int hour,int min,int sec);
    void testTime();
private:
    Time m_tTimer; // 声明朋友存在
};

#endif

Match.cpp

#include "Match.h"
#include <iostream>

using namespace std;

Match::Match(int hour, int min, int sec):m_tTimer(hour, min, sec)
{

}
void Match::testTime()
{
    m_tTimer.printTime();
    cout << m_tTimer.m_iHour << ":" << m_tTimer.m_iMinute << ":" << m_tTimer.m_iSecond << endl;
}

main.cpp

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

int main()
{
    Match m(6, 30, 50);
    m.testTime();

    system("pause");
    return 0;
}
要求

3-2-StaticMemberFunction

Tank.h

#ifndef TANK_H
#define TANK_H

class Tank
{
public:
    Tank(char code);
    ~Tank();
    void fire();
    static int getCount();
private:
    static int s_iCount;
    char m_cCode;
};

#endif

Tank.cpp

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

int Tank::s_iCount = 10; //构造函数之外,单独初始化

Tank::Tank(char code)
{
    m_cCode = code;
    s_iCount++;
    cout << "tank" << endl;

}
Tank::~Tank()
{
    s_iCount--;
    cout << "~Tank()" << endl;
}

void Tank::fire()
{
    cout << "Tank--fire" << endl;
}
int Tank::getCount()
//声明时添加static,定义时与普通一致
{
    return s_iCount;
}

main.cpp

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

int main()
{
    cout << Tank::getCount() << endl;
    //在类实例化之前就能使用
    Tank t1('A');
    cout << Tank::getCount() << endl;
    //初值10变成11
    cout << t1.getCount() << endl;

    // 堆上实例化自己管理内存
    Tank *p = new Tank('B');
    cout << Tank::getCount() << endl;
    Tank *q = new Tank('C');
    cout << q->getCount() << endl;

    delete p;
    delete q;

    cout << Tank::getCount() << endl;
    system("pause");
    return 0;
}

运行结果:

运算符重载要求

4-2-UnaryOperatorOverload

  • 成员函数重载

Coordinate.h

#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

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 &Coordinate::operator-()
{
    m_iX = -m_iX;
    this->m_iY = -this->m_iY;

    return *this;
}

main.cpp

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

运行结果:

要求

4-5-BinaryOperatorOverload

运算符的重载:对于加号运算符,输出运算符,索引运算符。

Coordinate.h

#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

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

main.cpp

#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;
}
要求

5-2-FunctionTemplate

main.cpp

#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;
}
要求

5-6-ClassTemplate

MyArray.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

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

运行结果:

链表
  • 链表会有一个头结点。每一个链表都由若干结点组成。
  • 一个结点都没有称之为空链表
  • 存在多个结点。第一个结点称之为头结点。
  • 对于每一个结点由两部分组成。一部分是数据部分(ABCDE都是数据域),还有一部分是指针部分。
  • 指针部分用来将结点串联起来。

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

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;

标准模板库代码实现

标准模板库

vector使用方法:

6-2-vectorPushBackPopFor

#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();//从尾部去除一个
    
    for (int i=0;i<vec.size();i++)
    {
        cout << vec[i] << endl;
    }
    cout << "end for" << endl;
    cout << vec.size() << endl;
    return 0;
}

运行结果:

迭代器版本: 6-2-2-IteratorVector

#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);
    
    //迭代器
    vector<int>::iterator itor = vec.begin();
    
    //cout << *itor << endl; // 打印出来的是第一个元素值
    
    for (;itor != vec.end();itor++)
    {
        cout << *itor << endl;
    }
    cout << "end iterator" << endl;
    cout << vec.front() << endl;//第一个元素
    cout << vec.back() << endl;//最后一个元素
    
    return 0;
}

运行结果:

这里请注意end获取到的是最后一个元素的下一个位置

标准模版库编码实现2

list的遍历代码:

6-3-ListOnlyCanUseIterator

#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;//错误

//  }
    return 0;
}

报错:

Type 'list<int>' does not provide a subscript operator

#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;
    }
    return 0;
}

map遍历:

6-3-MapIterator

#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); //错误,pushback不是map的成员
    
    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;
    }
    
    return 0;
}

运行结果:

string类型map

6-3-2-StringMap

#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; //输出key
        cout << itor->second << endl;//输出value
    }
    
    return 0;
}

运行结果:

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

单元巩固

使用vector存储数字3,6,8,4,并遍历。
使用map存储S-Shang Hai B-Bei Jing G-Guang Zhou,并遍历

6-5-VectorMapIterator

#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不能重名。

相关文章

网友评论

    本文标题:10-C++远征之模板篇-学习笔记

    本文链接:https://www.haomeiwen.com/subject/tydymftx.html