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等其他函数重载;
    • 静态变量&静态函数;
    • 虚函数/纯虚函数;(虚函数用于继承中的覆盖(有指针变量的话需要虚析构函数)纯虚函数用于做接口类型的类,是多个子类的父类,没有析构和构造函数);
    • 运算符重载函数;

posted on 2019-12-02 20:47  Nancy_Fighting  阅读(366)  评论(0编辑  收藏  举报

导航