zoukankan      html  css  js  c++  java
  • c++高级功能学习笔记

    面向对象的三大特征:封装+多态+继承

    一、C++之封装上

    1.c++类 封装

    (1) 原始类赋值:

    N.name="myy";
    N.age=10;
    

    正确赋值,将赋值封装进类定义的函数,这样就可以对赋值内容进行是否合法限制

    class Sudent
    {
        public:
        void setAge(int_age)
        {
            if(int_age>0&&int_age<100)
            {
                age=int_age;
            }
            else{...}
        }
    };
    

    (2) 若希望内部内容只被读取而不被改变–只读属性

    class Car
    {
        public:
            int get_num(){return num;}
        private:
            int num;
    
    };
    

    2. 内联函数和类内定义

    • 关键字:inline
      inline void fun {cout<<“Hello”<<endl;}
    • Inline函数省去了编译时函数调用的步骤,使编译更高效,但仅限于结构简单的函数,复杂函数编译器拒绝执行inline。
    • 类内定义
      • 类内定义:将函数声明及定义写在类内,对于简单函数会相同。

    3.构造函数初始化及定义

    //.h中声明
    class Car
    {
        public:
        Car(int num=1, string name="BMW");
    };
    //.cpp中定义,num, na
    
    me 不用再初始化
    Car::Car(int num, string name):n_num(num), n_name(name){}
    

    4. 拷贝构造函数

    • 当我们对自定义类进行拷贝操作时,不会重新调用构造函数,而是调用编译器自动生成的拷贝构造函数(如果没有自定义拷贝构造函数的话)。
    • 如果想自己构造拷贝构造函数,格式如下:
    • 定义格式:类名(const类名&变量名)
    • 如果没有自定义拷贝构造函数,系统会自动生成一个默认的。
    • 构造函数分类:
      • 无参构造函数
        • 默认构造函数
      • 有参构造函数
        • 参数带默认值
        • 参数无默认值
    • 代码示例:
    //.h声明
      class Teacher
      {
          public:
          Teacher (string name="Jim", int age=1);
          Teacher(const Teacher &tea)();//拷贝构造
          int age;
          string name;
      };
      //Teacher.cpp
       Teacher::Teacher(const Teacher &tea)
       {}
      //main.cpp使用
      //*拷贝构造在参数传递的使用中也能用到,代码示例test函数,内部的变量定义t生成时用的拷贝构造函数
      int main()
      {
        Teacher t1;
        Teacher t2=t1;
        Teacher t3(t1);
        return 0;
      }
    
    • 拷贝构造函数还会以参数传递的方式进行使用
    void test(Teacher t)//
      {
    
      }
      int main(void)
      {
          Teacher t1;
          tes(t1);//此操作使用了拷贝构造函数。
      }
    

    二、C++封装下

    2.1 对象数组

    int main(void)
    {
        Teacher t[3];
        t[3].name="lisa";//从栈中建立对象数组
        Teacher *p=new Teacher[3];
        p[0].name="Lisa";
        p[1].name="Tom";
        p[2].name="Jane";
        delete []p;//从堆中建立对象数组
        p=NULL;//p++即指向下一个对象元素,但是切记delete时,p的位置要回到第一个数组元素位置那。另外,P最后要指向NULL。
    }
    

    2.2 对象成员

    2.3 深拷贝与浅拷贝

    (1) 浅拷贝:对于非指针类型,直接拷贝值;对于指针类型,拷贝指针的值,而非指针指向的值,该种情况会造成程序崩溃。
    (2) 深拷贝:对于指针类型的值,新建一个指针,并将待拷贝元素指针所指向的值拷贝过来。

    • 代码示例
    //浅拷贝,无指针参数
    class Array
    {
      public:
      Array()Array(const Array &a)
      {
          m_ix=a.m_ix;
          m_iy=a.m_iy;
      }
      private:
      int m_ix;
      int m_iy;
    }
    
    //深拷贝,带指针拷贝
    class Array
    {
      public:
      Array()
      {
        m_iCount=5;
        m_iP=new int[m_iCount];
      }
      Array(const Array &a)
      {
          m_iCount=a.m_iCount;
          m_iP=new int[m_iCount];
          for(int i=0;i<m_iCount;i++)
          {
            m_iP[i]=a.m_iP[i];
          }//将指针所指向的内容进行拷贝
      }
      private:
      int* m_iP;
      int m_iCount;
    }
    

    2.4 this指针–类变量的地址

    (1) 传入的参数和类的数据成员不能重名,否则报错;

    Array(int len){this->len=len;}//这样就可以实现
    

    2.5 const 使用-带有const的,就不允许改变成员变量

    (2) 常成员函数

    • 函数不能对数据成员进行修改;
    • 常量构造函数,赋值只能用初始化列表方式
      • const Array::Array(int a):num(a){}
    • 格式: void change() const;
    • 重载: void change(); void change() const;互为重载函数,当变量定义为常量时,则调用常量函数,斗则调用普通函数。
    • const 函数重载目的是为了防止用户自定义一个const类,然后再调用类函数时出错,所以做的一个备用完善。如果用户不需要类const,则不需要该代码

    2.6 常指针与常引用

    (1) 常指针

    • 一般函数的this指针要求同时具有读和写权限,然而加const的变量只能有读权限,所以const变量调用函数时会有冲突报错,即使调用的函数不会改变成员变量的值,也因为有潜在风险,毕竟编译器不知道你在函数里定义了哪些操作,所以统统报错,只有函数后面加上const时,保证自己不会修改变量,此时编译器才不会报错。

    (2) 易混淆情况:

    • const Array *p=&n;
    • Array * const p1=&n;
    • 以上两个const指针含义不同,第一个是指指针指向的变量是常成员变量,该变量不能再进行修改值的操作; 而第二个定义的是常指针,即指针不能再指向其他变量。

    (3) 常引用:
    Array c1(2);
    const Array &c2=c1;
    此时c2是c1的别名,但是与c1不同的是,c2只有只读权限。

    三、继承篇

    3.1 继承篇

    • 前提:要继承的类,要完全包含于父类。子类只需要再补充自己特有的函数即可。(基类->派生类)
    • 内存关系:子类的内存等于父类的内存大小加上自己的特有的函数的内存大小。
    • 语法:
    class Worker : public Person
      {
      
      };
    
    • 在一个类中调用别的类,析构时先析构该类,再析构调用的类,类似层层剥茧;
    • 而析构一个继承了父类的子类时,要先析构子类,再析构父类,类似从尾到源式顺序。

    3.2 三种继承

    (1) 共有继承 class A:public B
    (2) 保护继承 class A: protected B
    (3) 私有继承 class A: private B

    • 公有继承

      • 父类的保护成员,可以被保护式的继承给子类,但是外部对象不可访问;
      • 父类的私有成员,不可被继承,因为无法访问。
    • 保护继承

      • 父类的公有成员和保护成员,都会被子类继承为保护成员
      • 私有成员同上
    • 私有继承

      • 父类的公有和保护成员,会被子类继承为私有成员;
      • 私有成员不被继承

    (4) has a 关系,不同于is a; 私有继承也是一种has a 关系

    3.3 隐藏

    • 父子关系
    • 成员同名
    • 隐藏: 当子类有与父类同名的函数或者数据变量时,定义的子类对象调用时会调用子类里的函数。而如果想要调用父类的变量时,格式为
    m.setName();//子类对象
    m.FL::setName();
    
    • 对于隐藏的两个对象,不会因为是否传入参数不同而形成重载,调用父类函数,只能用隐藏的语法。
      小知识补充:
      #include “”,用双引号则编译器会从文件目录去找头文件;如果用<>,则编译器会从安装包里包含的文件库找头文件。

    • 派生类可以赋值给基类,但是基类不能赋值给派生类。

    • 当子类给父类对象初始化时,父类只能接收两者共同部分的函数和数据值,对于子类独有的函数,父类不能被初始化

    • 当父类的指针指向子类对象时,也只能访问到两者的公共部分,而不能访问到子类独有的部分

    3.4 多继承和多重继承

    (1)多重继承:多代继承
    (2)多继承:一个子类有多个父类
    代码示例

    class Worker{};
    class Farmer{};
    class MirgrantWorker:public Worker, public Farmer{};
    


    (3) 菱形继承
    类A
    | |
    类B 类C
    | |
    类D

    • 类D中由于继承可能会有两份类A,造成不必要的内存占用,如何避免内存开销?-虚继承
    • 解决办法:
    • class B:virtual public A;
    • class C:virtual public A;
    • class D:public B,public C

    四、多态

    4.1 虚函数–静态多态VS动态多态

    多态形式是父类指针指向子类对象,所以如果子类中有指针数据成员,那个在子类构造时会申请一块内存。父类在析构时并不能析构子类的内容,会造成内存泄漏,所以父类需要虚析构函数
    (继承特性:如果delete父类指针,则只会销毁父类的函数;而delete子类指针,则父类和子类定义都会被销毁)
    (1) 静态多态(早绑定):同一对象收到相同的消息却产生不同的函数调用,一般通过***函数重载***来实现,在编译时就实现了绑定,属于早绑定。

    (2) 动态多态(晚绑定):不同对象在收到相同消息时产生不同的动作,一般通过虚函数来实现,只有运行时才能实现绑定,属于动态绑定,一般通过函数覆盖来实现

    (3) 覆盖: 虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖。若不是虚函数,仅父类和子类有同样函数,是为隐藏。

    4.2 虚析构函数

    (1) 动态多态在父类指针释放子类对象时造成内存泄漏,为了防止而在父类中使用虚析构函数。

    (2) 根据VS2019实践,即使子类对象中没有指针类型,只要使用了多态,析构函数就得用virtual;

    (3) 虚函数可被继承,当子类中定义的函数与父类中虚函数声明相同时,该函数就是虚函数;
    (4) virtual使用注意事项:

    • 普通函数不能使用,即不在类中的函数;
    • static 静态成员函数不能使用。
    • 不能使用内联函数,会被编译器视为纯虚函数;
    • 构造函数不能为虚函数

    (5) 虚函数与虚析构函数原理

    • 父类存在一个虚函数指针,指向一个虚函数表,在表中存有各虚函数的地址。因此开始执行时,当执行到虚函数,编译器会从虚函数表中找虚函数地址;对于在子类中覆盖的虚函数,子类也存在一个虚函数表,只不过对应位置上的指针地址改为子类所覆盖的函数地址。虚析构函数同理。
      寻址过程类似如下:
      shape
      |vftable|–>|…|
      |m_iEdg|         |calcArea_ptr|–>|calcArea|
      |m_dRR|

    (6) 代码证明虚函数表的存在
    概念说明

    • 对象的大小:类里定义的函数不占内存大小,只有数据成员占内存。对于没有任何数据成员的对象,为表示其存在,编译器给其内存大小为1;对于存在一个int型的对象,其内存占用大小为int型大小4字节。
    • 对象的地址:——
    • 对象成员的地址:在对象地址的头部开始
    • 虚函数表的指针: 在有虚函数情况下,实例化一个对象时,对象占用内存的第一块就是虚函数表的指针,占据内存大小4字节,然后依次是该对象的数据成员。
    • 如果子类没有覆盖父类的虚函数,则两张虚函数表中,某一虚函数指针指向同一个函数。

    4.2纯虚函数和抽象类

    (1)定义:只有函数声明,没有定义,且声明后加等于0;

    • 格式:
      virtual double calcPerimeter()=o;//纯虚
      virtual double calcArea(); //虚函数
      

    (2)虚函数表中,表指针指向的纯虚函数值为0; 而虚函数则指向一个具有实际意义的函数。
    (3)抽象类: 含有纯虚函数的类叫做抽象类

    • 由于含有纯虚函数原因,抽象类无法实例化对象
    • 抽象类的子类,如果没有定义父类的纯虚函数,那么它也是抽象类,无法进行实例化;
      (4)**接口类:**仅含有纯虚函数的类称为接口类
    • 及没有数据成员,只有纯虚函数;
    • 实际使用中,接口类更多用于表达一种能力或协议。
    • 比如父类定义了一些函数特性,那么子类必须实现这些函数,才从概念上说明子类属于父类。
    • Note that:
      • 抽象函数中只有纯虚函数,没有数据成员,构造函数和析构函数。
      • 接口类最常见用法是在定义全局函数时限制输入对象的类型,但是传入的所有数据都可以安全调用抽象类的纯虚函数,因为肯定已经被定义过了。
      • 可以使用接口类指针指向子类对象来实例化一个对象,并调用子类中实现的接口类中的纯虚函数。
    void flyMatch(Flyable *a, Flyable *b)
    {
      a->takeOff();
      a->land();
      b->takeOff();
      b->land();
    }  
    

    ctrl+k+u去掉注释;
    ctrl+k+c加注释

    4.3 RTTI(Run-Time Type Identification)-运行时类型识别

    RTTI的作用就是需要对对象成员进行动态判断时,用关键字来确定对象的动态类型。如引入的是父类类型指针指向的子类对象,但是继承父类的子类有很多,需要实时的根据不同的子类执行不同的操作,此时就需要RTTI了
    (1)关键字:dynamic_cast,以下是其注意事项:

    • 只能应用于指针和引用的转换;
    • 要转换的类型中必须包含虚函数;
    • 转换成功返回子类地址,失败返回NULL;
      (2)关键字: typeid,以下是其注意事项:
    • type_id返回一个type_info对象的引用;
    • 如果想通过基类指针获得派生类的数据类型,基类必须带有虚函数
    • 只能获取对象的实际类型。
      (3)示例代码
    void doSomething(Flyable *obj)//需要转换的只能是指针
    {
      if(typeid(*obj)==typeid(Bird))
      {
        Bird *b=dynamic_cast<Bird *>(obj);//要转换的类型中必须包含虚函数,子类继承父类的函数也是虚函数
      }
      if(typeid(*obj)==typeid(Plane))
      {
        Plane *p=dynamic_cast<Plane*>(obj);//如果想通过基类指针获得派生类数据类型,基类必须带有虚函数
      }
    }
    

    4.4 C++异常处理

    对可以预见的错误进行相应的处理,否则交由编译器处理的话会直接造成程序崩溃。
    (1)关键字:try…catch… throw

    • 说明:try.catch:将主逻辑放在try块里,异常处理模块放在catch里。
    • 在main函数中,用try,catch块进行异常捕获
    • 常见的异常有:数组溢出+除数为0+内存不足
      (2)实践:可以通过定义父类作为接口,然后接受各种子类异常。

    五、模板

    5.1 友元函数和友元类

    (1)友元全局函数:函数定义在全局,且在类中声明为友元,则在该函数中可以调用类的private成员;
    (2)友元成员函数:定义在类A中,且在类A的定义前要加入“class B;”,以告知编译器不需要报错。该函数需要在另一个类B中声明为其友元函数,且在B中需要Include 类A的头文件。形式为

    #include "A_class.h"
    class B_class
    {
    public:
    friend void A_class::printA(B_class &t);
    ...
    };
    

    (3)友元类:与友元函数类似,只需在类里面声明即可。形式为:

    class Circle;
    class Coordinate
    {
      friend Circle;
      public:
      ...
    };
    

    将Circle定义为友元类后,我们就可以在circle类中定义coordinate的对象,通过该对象,调用其私有数据类型和私有函数。
    (4)

    • 友元关系不可传递;
    • 友元关系单向;
    • 友元声明的形式及数量不受限制
    • 友元只是封装的补充,不推荐用,因为减弱了类的封装性。

    5.2 类中static

    • 应用场景:一个公司的系统,每新建一个用户,统计用户的num变量就++, num变量不依赖新用户或旧用户的生成或消失而生成或消失,但是却会因为新建一个用户而加一,注销一个用户而减1。外界可以随时调用静态成员查看num值。它依赖类存在而存在,不依赖对象存在而存在。
    • 静态数据成员
      • 注意事项:必须初始化;
      • 可被非静态和静态函数均可调用。
    • 静态成员函数
      • 注意事项:不能调用非静态数据成员;
      • 形式:
      class A
      {
        public:
        A(){num++;}
        ~A(){num--;}
        static num;
        static getNum{return num;}
      };
      int A::num=0;
      
    • 调用静态函数和静态成员时形式:
      //方式一
      int main(void)
      {
        cout<<A::getNUm()<<endl;
        cout<<A::num<<endl;
      }
      //方式二
      int main()
      {
        A a;
        cout<<a.num<<endl;
        cout<<a.getNm<<endl;
      }
      

    5.3 运算符重载

    (1)关键字:operator; 包括一元运算符重载、二元运算符重载等
    (2)以一元运算符(只需与一个变量进行运算)重载的-(负号)、++两个符号为例;

    • -(负号)的重载:友元函数重载+成员函数重载
      -负号函数重载代码示例
    //成员函数重载
    class coordinate
    {
      public:
      coordinate();
      ~coordinate();
      coordinate & operator-()
      {
        m_x=-m_x;
        m_y=-m_y;
      }
      privateint m_x;
      int m_y;
    };
    //友元函数重载
    class coordinate
    {
      friend coordinate & operator-(coordinate &c);
      {
        m_x=-m_x;
        m_y=-m_y;
      }
      public:
      coordinate();
      ~coordinate();
      privateint m_x;
      int m_y;
    };
    //friend function realization
    //coordinate..cpp
    coordinate & operator-(coordinate &c)
    {
      c.m_x=-c.m_x;
      c.m_y=-c.m_y;
      return c;
    }
    

    ++符号重载示例

    • 首先讲述一下,前置++,“++a”,表示本次操作结束后,a的值比原来大一;后置++,“a++”,表示的是本次执行结束后a的值不变,但是一旦执行下一条指令时a就会加一,值比原来大1。
    • 编译器为了区分这两种++,在指令传入时有所不同,这点需仔细对比两者代码。
    • 变量的返回也有不同,比如函数定义时,是否加引用&符号。
    • 以下编程示例中会着重讲解,需要认真理解。
    //前置++
    class Coordinate
    {
    public:
      Coordinate& operator++()
      {
        ++m_x;
        ++m_y;
        return *this;
      }
    };
    //后置++
    class Coordinate
    {
    public:
      Coordinate operator++(int)
      {
        Coordinate old(*this)//复制传入的变量值
        ++(this->m_x);
        ++(this->m_y);
        return old;//也就是说本次执行返回变量未加一之前的值;等下一个使用该变量的代码使用时,变量才变为原来的+1值。
      }
    };
    

    (3) 二元运算符重载:成员函数重载和友元函数重载

    • 第一个典型例子是+号的重载(友元和成员函数都可进行重载)
    • 成员函数+号重载
    class Coordinate
    {
      public:
        Coordinate(int x,int y);
        Coordinate operator+(const Coordinate &coor)//this指针表示+号左边值;coor为传入+右边值,但是返回一个新值给等号左边。传入的值为了保险起见,不能改变其值大小,所以加const.
        {
          Coorfinate m;
          m.m_x=this->m_x+coor.m_x;
          m.m_y=this->m_y+coor.m_y;
          return m;
        }
      private:
        int m_x;
        int m_y;  
    };
    
    • 友元函数+号重载
    class Coordinate
    {
      friend Coordinate operator+(const Coordinate &coor1,const Coordinate &coor2)
      {
        Coordinate m;
        m.m_x=coor1.m_x+coor2.m_x;
        m.m_y=coor1.m_y+coor2.m_y;
        return m;
      }
      public:
        Coordinate(int x,int y);  
      private:
        int m_x;
        int m_y;  
    };
    
    //main.cpp
    int main()
    {
      Coordinate p1(2,3);
      Coordinate p2(3,4);
      Coordinate p3(0,0);
      p3=p1+p2;
      return 0;
    }
    
    • “<<”输出运算符重载(只能友元函数重载)
      • 成员函数不可进行重载的原因:因为重载函数中首个参数必不包含对象的this指针,而是外部的cout的oostream类型引用,所以一定不能用成员函数进行重载。
      • 友元函数重载
    class Coordinate
    {
      friend ostream& operator<<(ostream &out, const Coordinate &coor)
      {
        out<<coor.m_x<<","<<coor.m_y;//该部分与cout形式一样
        return out;//务必要返回
      }
      public:
        Coordinate(int x,int y);  
      private:
        int m_x;
        int m_y;  
    };
    
    //main.cpp
    int main()
    {
      Coordinate coor(3,5);
      cout<<coor;
    }
    
    • []索引运算符(只能成员函数进行重载)该重载的更多运用在数组上
      • 因为索引的第一个参数一定是对象的this指针,而不能是别的,所以不能用友元函数进行重载
      • 成员函数重载代码实现:
    class Coordinate
    {
      public:
        Coordinate(int x,int y);  
        int operator[](int index)
        {
          if(index==0)
          {return m_x;}
          if(index==1)
          {return m_y;}
        }
      private:
        int m_x;
        int m_y;  
    };
    
    //main.cpp
    int main()
    {
      Coordinate c(3.5);
      cout<<c[0];
      cout<<c[1];
      return 0;
    }
    

    5.4 模板函数与模板类

    (1) 为什么要引入模板?
    对于只有参数类型不同,其他均相同的函数,为了定义方便,将参数类型作为变量传入函数模板.
    (2) 关键字:template typename class(typename 和 class可以混用)
    (3)计算机中,如果仅仅写出函数模板,而没有使用它,那么计算机是不会产生任何代码数据。只有当去使用函数模板才会产生实际代码
    (4) 函数模板及其语法

    • 类型作为模板参数
      template<class T>
      T max(T a, T b)//注意term name:函数模板
        {
          return(a>b)?a:b
        }
    
      //使用
      int main()
      {
        int m=max(100,90);//编译器可以自动根据检测到的数据类型进行计算;
        //term name:模板函数
        char n=max<char>('A','B');//也可以自己强制生成
      }
    
    • 常量值作为模板参数;需要注意的是不能使用浮点数,类,指针等作为模板参数,而且必须是确定的值,不能是变量。
    template<int size>
    void display()
    {
      cout<<size<<endl;
    }
    //使用
    int main()
    {
      display<10>();
    }
    
    • 多参数函数模板
    template<typename T,typename C>
    void display(T a, C b)
    {
      cout<<a<<""<<b<<endl;
    }
    
    template<class A, int size>//这部分决定了函数在使用时要给出的类型和变量值的结构形式
    void max(A a)//该部分决定了函数括号内部的结构
    {
      if(a>size)
      {
        cout<<a<<endl;
      }
      else
      {
        cout<<size<<endl;
      }
    }
    //使用
    int main()
    {
      int a=3; 
      char str='A';
      display<int,char>(a,str);//将声明的都指定出来即可
      max<int,5>(a);
    }
    
    • 函数模板与重载
      • 函数名相同,但输入类型不同的函数模板不是函数重载,因为在未使用之前,它们不会在内存中生成任何代码,只有在使用的时候,生成了代码,才会形成重载
    tempplate <typename T>
    void display(T a);
    
    tempplate <typename T,int size>
    void display(T a);
    
    tempplate <typename T>
    void display(T a, T b);
    

    (5) 类模板:适用于编写数据结构相关代码

    • 必须在头文件中全部定义,无法做到.cpp/.h分别编译;
    • 类模板外部定义的成员函数,每一个前面都需要加上模板<>声明。
    • 语法
    template<class T>
    class MyArray
    {
      public:
        void display(){...}//类内定义成员函数,与普通类无不同
        void setName(T mm);
        T Add(T a, T b);
        private:
        T *m_pArr;
    };
    template<class T>
    void MyArray<T>::setName(T mm)//每一个函数都需要重申一次
    {...}
    
    template<class T>
    T MyArray<T>::Add(T a, T b)
    {...}
    
    //使用时
    int main()
    {
      MyArray<int> arr;
    }
    

    情况二

    template<class T, int KSize>
    class MyArray
    {
      public:
        void display(){...}//类内定义成员函数,与普通类无不同
        void setName(T mm);
        T Add(T a, T b);
        private:
        T *m_pArr;
    };
    template<class T, int KSize>
    void MyArray<T,KSize>::setName(T mm)//每一个函数都需要重申一次
    {...}
    
    template<class T, int KSize>
    T MyArray<T,KSize>::Add(T a, T b)
    {
      a=b+KSize;
      return a;
    }
    
    //使用时
    int main()
    {
      int a=3;
      int b=4;
      MyArray<int,10> arr;
      arr.Add(a,b);//Add函数不需要再加<>类型声明
    }
    

    5.5 标准模板类

    (1)vector

    • vector v3(n,i);//含义为包含n个值为i的元素
    • vector v1(v3);//复制了一个v3
    • 常用函数
      empty()//返回是否为空
      begin()//返回首个元素
      end()//返回末元素的下一个元素
      clear()//清空向量
      front()//第一个数据
      back()//最后一个数据
      size()//返回大小
      push_back()//将数据插入向量尾
      pop_back()//删除向量尾部数据
    
    • 迭代器 iterator
    • 借助迭代器可以实现标准模板内部的遍历
    • 迭代器定义的元素一使用时一定要加, 这样才表示前迭代器所指向的元素*
    vector<string> vec;
    vec.push_back('A');
    vector<string>::iterator cite = vec.begin();
    for(; cite!=vec.end();cite++)
    {
      cout<<*citer<<endl;//
    }
    

    (2)链表

    • 链表的遍历只能通过iterator进行,不能使用普通的for循环
    • 插入速度大于向量

    (3)map 映射

    • key-value
    • 使用方法
      map<int,string> m;
      pair<int, string> p1(10,"shanghai");
      pair<int, string> p2(20,"beijing");
      m.insert(p1);
      m.insert(p2);
      cout<<m[10]<<endl;
      cout<<m[20]<<endl;
    
    • map的输出有两种方法,其中迭代器法需要注意。
      例子2
      map<string, string> m;
      pair<string, string> p1("S","shanghai");
      m.insert(p1);
      cout<<m["S"]<<endl;//
    //只能用迭代器遍历,且元素输出要注意
      map<string, string>::iterator ite=m.begin();
      for(; ite<m.end();ite++)
      {
        cout<<ite->first<<endl;//键值
        cout<<ite->second<<endl;//value
      }
    

    总结:

    • 类中可能定义的基本函数:
      • 构造、析构函数;
      • 拷贝构造函数(深/浅拷贝);//查询
      • const等其他函数重载;
      • 静态变量&静态函数;
      • 虚函数/纯虚函数;(虚函数用于继承中的覆盖(有指针变量的话需要虚析构函数)纯虚函数用于做接口类型的类,是多个子类的父类,没有析构和构造函数);
      • 运算符重载函数;
    Higher you climb, more view you will see.
  • 相关阅读:
    【甘道夫】通过Mahout构建贝叶斯文本分类器案例具体解释
    hdu 5044 树区间操作最后输出/ lca+dfs
    UVA 1371
    裴蜀定理
    iOS 开发系列:CoreData Object 变成 Fault 的一种方式
    UVa 10633
    校赛热身赛 Problem D. Unsolved Mystery
    校赛热身赛 Problem D. Unsolved Mystery
    NOIP2005普及组第4题 循环
    NOIP2005普及组第4题 循环
  • 原文地址:https://www.cnblogs.com/yyfighting/p/12500621.html
Copyright © 2011-2022 走看看