C++ 语言学习 day12 复习 (4)

1.模板

/**** 可以发现**************************************************
 * ①函数名相同,参数类型不同,模板函数可以与普通函数形成重载
 * ②当自己以及实现函数功能时,优先调用:已实现普通函数(原因CPU推到需要花时间)
 * ③调用有两种方式,自动类型推导 和 显示指定类型
 *      注意:我们经常用 显示指定类型(减少CPU推到时间)
 * ④模板的通用并不是万能的,在本案例中 数组就无法实现交换
 *      解决方案:自己实现普通函数高阶
 **************************************************************/

/********* 模板是动态绑定的: 也就是在调用时才产生 ******
 * 程序规则自上而下,从左往右:
 * 必须将模板放入同一文件
 * **********************************************/

代码:

#include <iostream>
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 <typeinfo> /* 打印类型信息 */
template <class Type> /*建立 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 <class Type> /*建立 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<double>(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 <iostream>
using namespace std;

/* 定义类模板: */
template <class Type>
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 <iostream>
#include "list.h" /*引入类模板*/

/****** 说过 #include 引入方式 *****
 * 自己工作路径 :   "头文件名"   -> 先工作路径 -> 系统目录 -> 结束
 * 系统库路径 :     <头文件名>   -> 直接系统目录 -> 结束
 * ******************************/

using namespace std;

/******* 类模板 *******
 * ①必须指定显示类型,在类名之后加<类型>
 * ②模板注意事项:
 *      1.程序自上而下,模板必须在同一文件
 *      2.类模板:尽量所有实现都写在同一文件
 * ******************/

int main()
{
    /**** 案例:int 类型 ****/
    list<int> 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 <iostream>
using namespace std;

/**** 父类是类模板 ****/
template <class Type>
class A
{
public:
    Type m_value;
};

/**** B去继承于A类模板 ***/
class B : public A<int> /**指定显示继承**/
{
public:
    string m_name;
};

template <class Type>
class C : public A<Type>
{

};

int main()
{
    A<int> v;

    B b;
    b.m_name = "李四";

    C<string> c;
    c.m_value = "10.5";
    cout << c.m_value << endl;

    return 0;
}


4.STL 容器的使用 (vector)

/*********** vector 容器:单端数组 ************
 * 头文件:#include <vector>
 * 命名空间: 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 <algorithm>
 *    push_back      了解迭代器知识
 *
    /***************** 迭代器 *****************************************************
     * 通过基础知识,我们可以发现 vector是连续空间,所以迭代器是 随机访问迭代器
     * 作用:用于算法和容器之间的胶合剂
     * 定义迭代器变量:
     *      容器类型<类型>::iterator  迭代器变量名;
     * 使用迭代器:
     *      针对于容器类型,能支持访问的都有
     *          iterator begin() Vs iterator end() ,可以发现都返回的是迭代子类型
     *          begin() : 首迭代子 -> 存放的是第一个元素的位置
     *          end()   : 尾迭代子 -> 存放的是末尾之后的元素位置,所以没有数据,只是做标记
     *      访问数据规则:可以将迭代子理解为指针,指针访问数据可以有两种方法: * 和 ->
     *      随机访问迭代器规则: ++,--,[]
     *
     *      template<typename _IIter, typename _Funct>
     *      _Funct for_each(_IIter首迭代子, _IIter尾迭代子, _Funct仿函数策略)
     *                                                   _Funct 原型 void func(Type value);
     * **************************************************************************/

代码:

#include <iostream>

/* ①引入头文件和命名空间 */
#include <vector>
/* ②引入通用算法库 */
#include <algorithm>

using namespace std;
/*********** vector 容器:单端数组 ************
 * 头文件:#include <vector>
 * 命名空间: 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 <algorithm>
 *    push_back      了解迭代器知识
 * ****************************************/
void test0()
{
    /*1.创建 存放int类型的实例化对象*/
    vector<int> 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<typename _IIter, typename _Funct>
     *      _Funct for_each(_IIter首迭代子, _IIter尾迭代子, _Funct仿函数策略)
     *                                                   _Funct 原型 void func(Type value);
     * **************************************************************************/
     vector<int>::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 Type>
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<int> 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 <vector>
#include <deque>    /*双端数组*/
#include <list>     /*链表*/
void test3()
{
    /**** 1.实例化STL对象 ****/
    vector<Person> 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<vector<Person>> v;

    {/*一班*/
        vector<Person> v1;
        v1.push_back(Person("张三",18));
        v1.push_back(Person("李四",17));

//        vector<Person>::iterator it;
//        for(it = v1.begin();it != v1.end() ;it++)
//        {
//            cout << *it << endl;
//        }

        v.push_back(v1);
    }

    {/*二班*/
        vector<Person> v2;
        v2.push_back(Person("李白",650));

        v.push_back(v2);
    }


    /**** 遍历打印:年级 ****/
    vector<vector<Person>>::iterator it_i;    /*定义迭代子*/
    for(it_i = v.begin();it_i != v.end();it_i++)  /*迭代子  *it_i => vector<Person> */
    {
        vector<Person>::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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值