zoukankan      html  css  js  c++  java
  • C++05模板

    C++模板

    友元函数

    关键字:friend

    友元全局函数:将全局函数声明为友元函数就是友元全局函数,可以访问到私有数据成员和私有成员函数。friend void printTime(Time &t);

    #include<iostream>` `using namespace std;` `class Time{` `friend void printTime(Time &t);` `public:` `Time(int hour,int minute,int second);` `private:` `int m_iHour;` `int m_iMinute;` `int m_iSecond;`
    };

    ==========================================

    #include "Time.h"
    Time::Time(int hour,int minute,int second){
    m_iHour=hour;
    m_iMinute=minute;
    m_iSecond=second;
    }

    =========================================

    #include<iostream>
    #include"Time.h"
    using namespace std;
    void printTime(Time &t){
    cout<<t.m_iHour<<":"<< t.m_iMinute<<":"<<t.m_iSecond<<endl;
    }
    int main(int argc, char *argv[]) {
    Time t(6,34,12);
    printTime(t);
    }

    友元成员函数:将成员函数声明为友元函数就是友元成员函数friend void Match::printTime(Time &t);

    #ifndef T_Time
    #define T_Time
    #include<iostream>
    #include"Match.h"
    using namespace std;
    class Time{
    friend void Match::printTime(Time &t);
    public:
    Time(int hour,int minute,int second);
    private:
    int m_iHour;
    int m_iMinute;
    int m_iSecond;
    ``
    };
    #endif

    ======================

    #ifndef M_match
    #define M_match
    class Time;
    class Match{
    public:
    void printTime(Time &t);
    };
    #endif

    ==========================

    #include<iostream>
    #include "Match.h"
    #include"Time.h"
    using namespace std;
    void Match::printTime(Time &t){
    cout<<t.m_iHour<<":"<< t.m_iMinute<<":"<<t.m_iSecond<<endl;

    }

    =======================

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

    int main() {
    Time t(6,34,12);
    Match m;
    m.printTime(t);
    }

    遇到的问题:由于多个文件引用同一个头文件时,没有使用#ifndef和#endif就出现了redefinition的问题

    image-20201119201126392

    解决办法:

    文件中的#ifndef
    头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。
    还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:
    #ifndef <标识>
    #define <标识>
    ......
    #endif
    <标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h
    #ifndef STDIO_H
    #define STDIO_H
    ......
    #endif

    友元类

    关键字:friend

    声明了某个函数的友元类之后,此友元类可以访问到该类的所有属性和方法。

    友元关系不可传递。

    友元关系的单向性。

    友元声明的形式(友元类/友元函数)以及数量(一个类可以有多个友元类)不受限制。

    友元只是封装的补充。破坏了封装性,定向暴露,不建议使用。

    注意:

    1、在做练习题的时候有一个错误地方,就是构造函数的定义要加{};声明是不需要。

    2、在A类中声明friend class B的意思是,B是A的友元类,B可以访问A的成员函数和属性。

    static

    在数据成员和成员函数之前加上static就变成了静态数据成员和静态成员函数。

    普通数据成员和静态数据成员:

    静态的依赖类。静态成员函数中,并不传入this指针,无法调用非静态数据成员,同时也不可以加上const关键字,但是可以调用静态成员或者全局成员。

    注意事项:

    静态数据成员必须单独初始化(在构造器之外),因为它并不随着对象的产生而产生,而是随着类的产生而产生。

    静态成员函数不能调用非静态成员函数和非静态数据成员,后者可以调用前者。

    运算符重载

    给原有的运算符赋予新的意义。

    成员函数的运算符重载:

    #include<iostream>` `using namespace std;` `class Coor{` `public:` `Coor(int x,int y);` `Coor &operator-();` `int getX();` `int getY();` `private:` `int m_iX;` `int m_iY;` `};

    =========================

    #include"Coor.h"
    Coor::Coor(int x,int y){
    m_iX=x;
    m_iY=y;
    }
    int Coor::getX(){
    return m_iX;
    }
    int Coor::getY(){
    return m_iY;
    }
    Coor &Coor::operator-(){
    this->m_iX=-this->m_iX;
    this->m_iY=-this->m_iY;
    return *this;
    }

    =============================

    #include"Coor.h"
    #include<iostream>
    using namespace std;
    int main(){
    Coor c(1,2);
    cout<<c.getX()<<","<<c.getY()<<endl;
    -c;
    cout<<c.getX()<<","<<c.getY()<<endl;
    }

    友元函数的运算符重载:

    	#include<iostream>
    using namespace std;
    class Coor{
    	friend Coor &operator-(Coor &c);
    	public:
    		Coor(int x,int y);
    	int getX();
    	int getY();
    private:
    	int m_iX;
    	int m_iY;
    }; 
    

    =======================

    #include"Coor.h"
    Coor::Coor(int x,int y){
    m_iX=x;
    m_iY=y;
    }
    int Coor::getX(){
    return m_iX;
    }
    int Coor::getY(){
    return m_iY;
    }
    Coor &operator-(Coor &c){
    c.m_iX= -c.m_iX;
    c.m_iY= -c.m_iY;
    return c;
    }

    ============================

    #include"Coor.h"
    #include<iostream>
    using namespace std;
    int main(){
    Coor c(1,2);
    cout<<c.getX()<<","<<c.getY()<<endl;
    -c;
    cout<<c.getX()<<","<<c.getY()<<endl; return 0;
    }

    ++运算符重载,前置++和后置++用(int)来区分,带(int)是后置。

    ** 二元运算符的重载**

    +号运算符可以用成员函数也可以用友元函数重载。

    输出运算符''<<''不可以使用成员函数重载,必须使用友元函数重载。因为第一个对象必须是ostream对象。

    索引运算符''[]''不可以使用友元函数重载,必须使用成员函数重载。因为第一个必须是该类自身的对象。

    练习:

    #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--(){
           m_iX--;
           m_iY--;
       }
       // 后置--运算符重载
       Coordinate &operator--(int){
            m_iX--;
            m_iY--;
       }
       // +号运算符重载
       Coordinate operator+(Coordinate c1){
            Coordinate temp(0,0);
            temp.m_iX=this->m_iX+c1.m_iX;
            temp.m_iY=this->m_iY+c1.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;
    }
    

    模板函数和模板类

    模板函数

    将类型作为参数。

    关键字:template、typename、class

    函数模板:

    template <typename T,class C>

    T max(T a,T b){

    return (a>b)>a:b;}

    通过函数模板产生的函数时模板函数。

    函数模板与重载:函数模板只有在使用的时候,产生出来的函数之间才是重载的关系。

    #include<iostream>
    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 size>
    void display(T a){
    for(int i=0;i<size;i++){
    cout<<a<<endl;
    }
    }
    int main(){
    display<int>(10);
    display<double>(12.2);

    display<int,double>(2,33.3);

    display<int,10>(7);
    return 0;
    }

    函数模板参数个数如果为0个,则没有必要使用函数模板

    练习:

    #include <iostream>
    using namespace std;

    /**

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

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

    类模板

    只有数据类型不同。

    关键字:template 、class

    template

    class M{

    public:

    ...

    void display();//在有类模板的条件下,类内的成员函数的定义每有什么不一样。

    private:

    T *m_pArr;//类内数据类型。

    };

    当成员函数在类外定义的时候:

    template

    void M::display(){
    }

    模板代码不能分离编译。不能将声明和定义在.h和.cpp中分开写。必须都写在.h中。

    练习:

    #include <iostream>
    using namespace std;

    /**

    • 定义一个矩形类模板Rect
    • 成员函数:calcArea()、calePerimeter()
    • 数据成员:m_length、m_height
      */
      template<class 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>::calePerimeter()
      {
      return m_length * m_height;
      }

    /**

    • 周长方法实现
      */
      template<typename T>
      T Rect<T>::calcArea()
      {
      return ( m_length + m_height) * 2;
      }

    int main(void)
    {
    Rect<int> rect(3, 6);
    cout << rect.calcArea() << endl;
    cout << rect.calePerimeter() << endl;
    return 0;
    }

    标准模板类

    C++标准模板库:STL(Standard Template Lib)

    vector向量

    本质时对数组的封装。vector的大小可以根据元素数量改变。

    1、初始化:

    image-20201120154925558

    2、常用方法:

    image-20201120155003630

    3、例子:

    #include<iostream>
    #include<vector>
    #include<list>
    #include<map>
    using namespace std;
    int main(){
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(3);
    vec.push_back(4);
    for(int i=0;i<vec.size();i++){
    cout<<vec[i]<<endl;
    }
    vector<int>::iterator itor=vec.begin();
    for(;itor!=vec.end();itor++){
    cout<<*itor<<endl;
    }
    cout<<vec.front()<<endl;
    cout<<vec.back()<<endl;
    vec.pop_back();
    cout<<vec.size()<<endl;
    return 0;
    }

    4、向量的遍历:for循环像遍历数组那样;或者使用迭代器iterator

    list链表

    list[i]不是实现,所以list的遍历可以用迭代器来实现。

    #include<iostream>
    #include<vector>
    #include<list>
    #include<map>
    using namespace std;
    int main(){
    list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.push_back(4);
    list<int>::iterator i=l.begin();
    for(;i!=l.end();i++){
    cout<<*i<<endl;
    }
    return 0;
    }

    map映射

    image-20201120155810722

    map中没有push_back,使用的时insert。使用迭代器的时候,因为是键值对,所以要分别输出key和value

    #include<iostream>
    #include<vector>
    #include<list>
    #include<map>
    #include<string>
    using namespace std;
    int main(){
    map<int,string> m;
    pair<int,string>p1(1,"GOT7");
    pair<int,string>p2(2,"Hello");
    m.insert(p1);
    m.insert(p2);
    for(int i=0;i<m.size();i++){
    cout<<m[i]<<endl;
    }
    map<int,string>::iterator it=m.begin();
    for(;it!=m.end();it++){
    cout<<it->first<<endl;
    cout<<it->second<<endl;
    }
    return 0;
    }

    练习:

    #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);
    //循环打印数字
    for(int i=0;i<vec.size();i++){
        cout<<vec[i]<<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 it=m.begin();
        for(;it!=m.end();it++){
            cout<<it->first<<endl;
            cout<<it->second<<endl;
        }
        return 0;
        }
    

    当map的key和value都是string类型的时候,好像只可以使用iterator来遍历。使用cout<<m[i]<<endl;是不可以遍历出来的。

  • 相关阅读:
    linux常用命令:
    解决css添加padding后元素变长的问题
    Hbase常用命令
    集群部署的三种方式(hadoop集群部署三种方式)
    linux编译安装指定依赖的软件包
    vue使用Element隐藏侧边栏进度条
    css相对于父容器,固定放在底部并撑满
    java中23种设计模式
    adb remount'的作用是什么?在什么情况下有用?
    java常用http请求库
  • 原文地址:https://www.cnblogs.com/yunxiaoqian/p/14014646.html
Copyright © 2011-2022 走看看