C++学习总结

什么是C++

C++是一门编程语言

C++是在C语言的基础上发展起来的,C++继承了C语言的全部功能。

 C++完全兼容于C语言,C语言编写的代码可以在C++的环境下进行编译和运行,C语言编写的代码可以与C++语言编写的代码一起混编。

C语言是面向过程的,C++是面向对象的。

什么是C++中的类

C++中的类和C中的结构体非常相似,类是用来封装属性和函数的一种自定义的数据结构,类还具有继承、多态等多种形式。
1) C中的结构体与C++中的结构体的区别: C语言中的结构内只能有属性,而C++中的结构体可以包含属性和方法。
2) C++中结构体与类的区别
权限访问限定符:
private:微信的支付密码,只有我自己知道。只能在类的作用域内访问。
protected:保护成员,相当于微信好友,只有我允许才能看我的动态,不能在类的外部访问,但可以在继承关系的子类中访问父类的protected成员。
public:公开成员,相当于微信的公众号,public修饰的成员可以在类的外部访问。

默认情况下,结构中的成员权限默认为public,而类中的成员默认为private。

3)this指针
在类的方法内部,this指针指向该类实例化后的对象,this指针是一个特殊的指针。
(1) 在C++类的方法内部,this用来指向调用该函数的对象,this指针是一个常量指针,它的值不能被修改。
(2)在类的方法内部,可以用this指针来访问类的属性和调用类的方法。

什么是封装

把方法和属性集中在一个类中,且方法是用来操作属性的做法就叫封装。
为什么需要封装:
1) 人性化的设计; 
2) 保护数据成员,避免外部破坏对象的属性数据;
3)体现了模块化的程序设计思想,在面向过程的编程思想中,因为数据和函数是相互分离的,某些函数可能 意外的修改了不属于它的数据,从而造成了程序错误。
而在面向对象的程序设计思想中,数据和操作它的方法被捆绑在了一起构成了对象,而数据是作为对象的私有数据,只能由与数据捆绑在一起的方法来访问,这样就避免了数据 被其它函数意外的修改。
构造函数与析构函数

构造函数与析构函数

构造函数

(1)构造函数与类名相同,没有返回值;
 (2) 在对象被创建时由系统自动调用
 (3)构造函数的作用是用来初始化该对象的属性。
 
-->默认情况下,定义一个类时,系统会为该类提供默认构造函数,默认构造函数不带参数。
-->如果定义类时,为类提供了一个自定义的构造函数,那么在实例化类对象时就会调用该自定义的构造函数,而默认的构造函数会被自定义的构造函数取代。
 

析构函数

(1)析构函数在类名前加~
(2)在对象被销毁时由系统自动调用
(3)作用是释放对象占用的资源


C++中的默认参数

1)在C++的函数中可以有默认参数,不论是类的成员函数还是全局函数都可以有默认参数,而C语言中的函数没有默认参数。
(1)在定义函数的时候,可以给函数的形参设置一个默认值,如果在调用函数时给函数传递了实参,则参数的值就是实参的值,如果没有传递实参,该参数就使用默认值。
(2)可以有多个默认参数,但是默认参数的默认值 设置顺序必须按照从右到左的顺序依次设置,中间不能有间断。
(3)实参在给形参传值是从左到右进行传递的。
(4)函数在声明的时候有默认参数时,在定义函数的时候就可以省略默认参数。
(5)默认参数和函数重载一起使用时容易产生二义性。
 

C++中函数的重载

重载:简单来说,函数的重载是指,函数名称相同,参数列表不同的情形叫重载(和返回值无关)。
这样的同名不同参数的函数之间,互相称为重载函数。
为什么C++支持函数的重载,而C语言不支持函数的重载?
(1)C语言是依赖函数来识别函数的,而C++的函数名由函数的返回值和参数列表构成。
 

C++中的赋值

C语言中的赋值用 = 
C++中的赋值可以使用() , 如:int a(b);
 

c++中的引用

一个变量可以有多个名字,甚至多个名字。
引用实际上与所引用的变量占用的是同一个内存空间。
对引用的操作等价于对变量的操作,不会为引用分配内存空间,引用和被引用的变量共享同一内存空间。
一个变量可以有多个引用,一个引用只能对应一个变量。
引用关系一旦形成,不能更改。

函数的参数为引用类型时,在调用函数时不会为该参数分配内存空间,仍然引用实参的内存空间。
函数的参数为非引用类型时,在调用函数时要进行赋值拷贝,为形参分配内存空间。

(1),指针是一个实体需要为其分配内存空间,而引用是一个变量的别名,只会共享同一内存空间。
(2)引用在定义的时候必须对其进行初始化,而指针在定义时可以不初始化。
(3)有多级指针,没有多级引用,引用只能一级。
(4) 指针的自增运算指向的是下一个空间,而引用的自增运算变量值 加1
(5)sizeof对引入得到的是引用类型的大小,而sizeof对指针得到的是指针本身的大小。
(6)可以有void * 类型的指针,但不能有void型的引用
(7)可能有指针数据,函数指针,不能有数组引用和函数引用。

const 修饰符
const 关键字在C++类成员函数后面,表示这个函数不能修改类中的任何属性。

mutable关键字,成员变量声明时在前面加上mutable关键字,可以在const修饰的函数中修改其值。

C++中的内存分配
(1)C++中用new分配内存,用delete释放内存

new delete与 malloc free的区别
(1) new 和delete是关键字,而malloc和free是函数需要包含头文件并引用函数库。
(2) malloc返回的是void *指针,需要强制类型转换才能赋值,而new返回的是特定类型的指针,不需要强制类型转换。
(3) new申请内存的时候已经确定内存中存放的数据类型,new会做类型检查,即指针的数据类型必须和new后面的数据类型一致。
(4)malloc申请内存时需要指定大小,new只需要指定元素的个数和类型即可。
(5) new创建一个对象时会调用对象的构造函数,delete释放一个对象指针时会调用对象的析构函数。

作用域
(1) 函数域
(2) 匿名域
(3) 全局域
(4) 类域
(5) 文件域
(6) 名字空间域

名字空间 (命名空间)
名字空间就是一个作用域,目的是为了防止名字冲突,用namespace来定义
匿名名字空间中的变量和函数相当于用static修饰的变量和函数,只能在本文件范围内使用。

名字空间的作用:
(1)防止名字冲突

::  域名符号

objdump 命令的用法
objdump -x |grep ***

输入输出流

C++中的lambda表达式
https://baijiahao.baidu.com/s?id=1764204752336882618&wfr=spider&for=pc

1) Lambda表达式的介绍

c++11引入了Lambda表达式,使得开发人员可以更方便的创建匿名函数。Lambda表达式是c++语言的一个重要特性,它可以作为函数对象使用,可以用来替代一些繁琐的函数声明和定义。

2) Lambda表达式的语法

Lambda表达式的基本语法结构如下:

[capture list] (parameter list) specifiers exception -> type { function body }
[&]{};          // OK:默认以引用捕获
[&, i]{};       // OK:以引用捕获,但 i 以值捕获
[&, &i] {};     // 错误:以引用捕获为默认时的以引用捕获
[&, this] {};   // OK:等价于 [&]
[&, this, i]{}; // OK:等价于 [&, i]

[capture list]是捕获列表,在应用中必填,是用来表示 该lambda 要使用的外部已经定义的变量。

(parameter list)是参数列表,在应用中选填。

-> type是返回值类型,在应用中选填。
 

类的静态属性和静态方法

在类中定义属性和方法时在其前面加上static关键字,这样的属性叫静态属性,这样的方法叫静态方法。

类的静态成员变量

1)类的静态成员变量在使用前必须进行初始化。类的非静态成员变量可以在定义时直接初始化。而类的静态成员需要在类的定义外单独初始化。
2)类的静态成员变量属于类,静态成员变量在程序启动时已经在全局的数据段中为其分配了内存空间,不属于任何对象,静态成员变量相当于全局变量,只是要通过类名::变量名,或者对象名.变量名的方式来访问。相当于定义了一个全局变量,只是在该全局变量的外面加了一层作用域。
3) 用sizeof来获取类的大小时,静态变量不计算在内。
4)类的静态成员在使用时必须被初始化。
5)类的静态成员在访问时也受权限访问限定符限制。
6)在静态成员函数中不能使用this指针,因为静态成员不属于任何对象,也就没没有this指针。

C++中的继承

在多个类的定义中,子类包含了父类的属性和方法,同时子类又有扩展了自己的属性和方法,就可以说子类继承了父类。
1,成员初始化列表
在类的构造函数后加: ,再列出要初始化的成员,并为其赋值,
1)用于子类的构造函数为父类的构造函数传递参数
2)用于初始化该类中的属性
3)类中的常量或引用类型的属性在使用前必须被初始化,可以在定义类定义时进行初始化,也可以使用成员初始化列表的方式进行初始化。
4)成员初始化列表的执行顺序,是按照变量在类中的声明顺序进行的,而与成员初始化列表中的顺序无关。

2,继承中构造函数的执行顺序,析构函数的执行顺序
1), 在实例化类对象时,会先调用父类的构造函数,再调用子类的构造函数。
2), 在对象被销毁时,析构函数的执行顺序是子类后父类。

3,在子类中怎样调用父类的同名函数
在子类的函数中通过父类的类名加上::来调用父类的同名函数。

4,拷贝构造函数
1)拷贝构造函数也是构造函数重载的一种形式,与普通构造函数不同的是它的参数为该类 类型的常量引用。
2)如果类没有自定义拷贝构造函数则系统会自动为其生成一个默认的拷贝构造函数,此默认的拷贝构造函数为浅拷贝。
3)拷贝构造函数的作用是用另一个该类型的对象来初始化此对象。

(1)浅拷贝:在构造函数中把作为参数的对象属性直接赋值给新对象的属性
(2)深拷贝:在构造函数中为新对象的指针变量重新分配内存,然后再用参数对象指针所指向的内存来初始化新对象指针指向的内存。

5,拷贝构造函数调用的时机
(1)用()来传递参数时
(2)用=符号对新对象进行赋值时。

6,explicit

C++中,具有一个参数的构造函数,承担了两个角色
一是起构造函数的作用,二是承担默认的类型转换功能。

如 class A = x,这样的代码,且恰好x的类型与A的只带一个参数的构造函数参数相同,这时编译器就会自动调用这个构造函数,创建一个对象时,在某些情况下,这样违背了我们的本意,这时候就要在这个构造函数前面加上explicit修饰符,指定这个构造函数只能被明确的调用,不能作为类型转换操作符被隐含调用。
 

继承关系中父子类之间的类型转换

1,向上类型转换: 把子类对象赋值给为父类类型的对象时会自动进行类型转换,把子类类型转换为父类类型,这种转换是安全的。
2,向下类型转换: 把父类类型的对象赋值给子类类型的对象时,要进行强制类型转换,并且这种转换是不安全的。
 

多态

1,没有在父类的函数前面加 virtual 时,用父类的指针指向派生类对象时,调用派生类与父类同名的函数时,调用的是父类函数。

2,在父类的函数前面加 virtual 时,用父类的指针指向派生类对象时,调用派生类与父类同名的函数时,调用的是子类函数。

3,基类有虚函数的(即在函数的返回值前加上virtual关键字),当用基类指针指向派生类对象时,调用该虚函数时实际上调用的是派生类的函数。

3,虚函数表
(1)基类中若有虚函数(函数前面加上关键字virtual),则以这个类或该类的派生生成的对象中就会有一个虚函数表的指针,一般位于对象占用空间的起始处。
(2)虚函数表中存放的是虚函数的地址,即虚函数指针。

(3) 虚函数是有继承的,若父类中的某个函数为虚函数,而子类没有重写此函数,则子类会继承父类的此虚函数。
(4)虚表是继承的,如果子类没有重写父类的某个虚函数,那么子类的虚函数表中保存的仍然是父类中该函数的地址,如果子类重写了父类中相应的虚函数,那么子类的虚函数表中保存的就是子类自身的虚函数地址,如果子类新增了自己的虚函数,那么虚函数表中也会添加该项。
(5)派生类的虚函数表中的虚函数的排列顺序和基类的虚函数表中虚函数地址的排列顺序相同。

3,虚表中虚函数的顺序
(1)无虚函数覆盖的情况
虚函数按照其声明顺序存放于虚表中,子类的虚函数放在父类的虚函数后面。
(2)被子类覆盖的函数放在了虚表中父类原先虚函数的位置,没有被覆盖的仍然是先父后子依次排列。

4,多态
基类有虚函数的,当用基类指针指向此基类的派生类对象时,在调用该虚函数时,实际上调用的是子类的虚函数,是按照虚表中实际存放的函数地址来调用的。

5,多态的作用
(1)应用程序不必为每一个派生类编写功能调用函数,只调用基类的方法就可以达到调用派生类函数的目的。提高了程序的可复用性。

(2)不同的派生类的不同功能,可以被基类的同一个方法调用,提高了程序了可维护性和可扩展性,实现了接口不变的特性。

基类有虚函数的,当用派生类对象指针赋值给基类指针时,不会进行类型转换。
基类没有虚函数的,当用派生类对象指针赋值给基类指针时,会进行隐含的向上类型转换。

6,纯虚类(抽象类,接口类)
(1)如果一个类中定义了一个虚函数,该函数的声明后添加了"=0",则此函数为纯虚函数。
(2)如果一个类中至少有一个纯虚函数,则此类为纯虚类,也叫接口类 或 抽象类
(3)纯虚类不能用来实例化对象。
(4)派生类如果没有实现父类的所有纯虚函数,则该派生类也是纯虚类,该派生类也不能用来实例化对象。
(5)纯虚类只能用来定义指针,不能用来实例化对象。

纯虚类的作用是用来定义接口的,让其派生类来实现。
 

怎样声明一个类

class <类名>
1,如果在一个类的函数定义中或者属性定义中要使用另一个类的引用或者指针类型,在不能包含头文件的情况下,就可以使用类声明来通过编译。

2,如果在一个类的函数定义中或者属性定义中要使用另一个类类型,则需要包含另一个类的头文件。

友元函数

友元函数的声明可以放在类的私有部分,也可以放在类的公有部分,它们是没有区别的,都说明此函数是该类的一个友元函数。
一个函数可以是多个类的友元函数,需要在各个类中分别声明,友元函数与类的关系不能被子类继承。
友元函数的调用与一般函数的调用方式和原理一致。
友元函数不属于类的方法成员。
在友元函数中可以访问宿主类用private\protected\public 限定的成员。

友元函数的声明方法:

class XXX
{
    ...
    friend <函数的原型>;
    ...
};
 

友元类

友元类就是在一个类的定义中声明另一个类为该类的友元类,在该友元类中的方法中就可以访问该类用private/protected修饰的成员。

友元类的声明方法:

class YYY
{
    ...
    ...
};

class XXX
{
    ...
    friend class YYY;
    ...
};

友元成员函数

把一个类的某个成员函数声明为另一个类的友元函数,这样,在这个友元成员函数中就可以访问宿主类中用private/protected所修饰的属性和方法。

class YYY
{
    ...
    void function(XXX & x);
    ...
};

class XXX
{
    ...
    friend void YYY::function(XXX & x);
    ...
};
 

运算符重载(操作符重载)

运算符重载实质上就是函数重载的一种,形式,目的在于能够用同名的函数来完成不同的基本操作,要重载运算符需要使用被称为运算符函数的特殊函数形式。
1,运算符重载的形式--全局函数运算符重载
<返回类型> operator <要重载的运算符>(<参数列表>)
{
    <函数体>
}

2,可重载的运算符列表
算术运算符: +, -, *, /, %, ++, --
位操作运算符: &, |, ^(位异或), <<(左移), >>(右移)
逻辑运算符: !, &&, ||
比较运算符: <, >, >=, <=, ==, !=
赋值运算符: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
其它运算符: [], (),->, new, delete, new [], delete[], * 指针运算符

3,运算符重载的形式--类成员函数运算符重载
1,对于前++ 和后++,需要用int参数来区分,有int参数的是后++,无int参数的是前++
CPoint& operator++(int); //后++
CPoint& operator++();    //前++
 

输入输出流

C++提供了三种输入输出流
“流”即是流动,是物质从一处向另一处流动的过程。具体到这里,是对一种有序、连续、有方向性的数据(其单位可以是bit,byte,packet)的抽象描述
1,标准输入输出流
"<<" ">>" 是在输入输出中被重载的与流和方向相关的运算符
在<iostream>头文件中被重载,使其能够用于标准类型数据的输入和输出,所以在使用标准输入输出时要包含头文件#include <iostream>

cout  << 5 ;
cin >> i;

istream:常用于接收从键盘输入的数据;
ostream:常用于将数据输出到屏幕上;
ifstream:用于读取文件中的数据;
ofstream:用于向文件中写入数据;
iostream:继承自 istream 和 ostream 类,因为该类的功能兼两者于一身,既能用于输入,也能用于输出;
fstream:兼 ifstream 和 ofstream 类功能于一身,既能读取文件中的数据,又能向文件中写入数据。

cout, cerr, clog的功能一样。

cin 输入流对象常用成员方法
getline(str,n,ch)    从输入流中接收 n-1 个字符给 str 变量,当遇到指定 ch 字符时会停止读取,默认情况下 ch 为 '\0'。

get()    从输入流中读取一个字符,同时该字符会从输入流中消失。

gcount()     返回上次从输入流提取出的字符个数,该函数常和 get()、getline()、ignore()、peek()、read()、readsome()、putback() 和 unget() 联用。
peek()    返回输入流中的第一个字符,但并不是提取该字符。
putback(c)     将字符 c 置入输入流(缓冲区)。
ignore(n,ch)    从输入流中逐个提取字符,但提取出的字符被忽略,不被使用,直至提取出 n 个字符,或者当前读取的字符为 ch。
operator>>    重载 >> 运算符,用于读取指定类型的数据,并返回输入流对象本身。

2,C++中流的状态,一共有四种状态,这些流的状态用标志位来表示,都是ios类的成员,如下:
1) batbit 发生了致命错误,流无法继续使用
2) eofbit 输入结束,文件流物理上结束了,或者是用户按下了Ctrl+z或Ctrl+c结束
3) failbit io操作失败,主要是操作了非法数据,流可以继续使用,输入结束后也将流设置为failbit
4) goodbit 一切正常,没有错误发生

3,C++提供了一些函数用来提供流的状态
good() 判断流是否是goodbit状态
bad() 判断流是否处于badbit状态
eof() 判断流是否处于eofbit状态
fail() 判断流是否处于failbit状态
clear() 清除流的状态

ios::app (append)追加模式。所有写入都追加到文件末尾。
ios::ate (at end)初始位置:文件尾,文件打开后定位到文件尾;
ios::in 打开文件用于读取。
ios::out 打开文件用于写入。
ios::trunc(truncate)如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。
字符串的输入输出流

C++提供了两种字符串流
strstream 是在strstream中定义
sstream 是在sstream中定义
它们实现的功能基本一致

可以实现把内存数据输入到字符串流对象中
可以实现类型转换
可以获得string类的对象。


模板

C++中模板是支持参数化多态的工具,就是让类或者函数声明为一种通用类型,使得类中的某些数据成员或者成员函数的参数、返回值在实际使用时确定类型。使用模板的目的就是能够让程序员编写与类型无关的代码,模板也是泛型编程的基础。
模板是一种对类型进行参数化的工具,通常有两种形式:
    1,函数模板
    函数模板针对仅参数类型不同的函数,参数类型不一样,但是功能及函数名一致的函数定义方式如下:
    template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表
    {
    函数体
    }
    
    2,类模板
    在类的定义中对属性或方法采用可变类型进行声明和定义,可变类型由模板的类型参数给出。
    
    template <typename 类型形参1, typedef 类型形参2>
    class <类名>
    {
    };
    
    注意:
    (1)模板的声明或定义只能在全局,命名空间或类范围内进行,即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板
    (2) 声明模板的数据类型关键字即可以是class也可以是typename
    
    3,模板的类型参数
    模板形参表示的是一个示确定的类型。模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型说明符或类类型说明符的使用方式完全相同,即可以用于指定返回类型,变量声明,函数参数类型等,类型形参仅由关键字class或typename后接说明符构成。
    
    4,模板的非类型参数
    模板的非类型参数,可以由C++内置的类型,或者自定义的类型。
    
    5,模板的默认类型参数 包括两种,一种是默认类型参数,一种是默认值参数
    类模板可以具有类型形参或值形参的默认实参。使用等号=后跟类型名称或值来指定默认参数。对于多个模板参数,第一个默认参数后的所有参数必须具有默认参数。声明带默认参数的模板对象时,请省略参数以接受默认参数,如果没有非默认参数,请不要忽略空尖括号。

构造函数和重载赋值运算符的调用时机

以CPerson为例
1, 调用拷贝构造函数的时机,以CPerson为例, 若CPerson没有提供拷贝构造函数,则系统会自动为其生成一个浅拷贝构造函数,
若CPerson提供了自定义的拷贝构造,则会调用该类提供的拷贝构造函数
CPerson per1;
CPerson per2(per1);

2,若为CPerson提供了拷贝构造函数,比如深拷贝,系统在生成对象时就会调用该类的深拷贝构造函数
若在CPerson的拷贝构造函数前加上explicit关键字,则编译无法通过
CPerson per1;
CPerson per2 = per1;

3,若没有为CPerson提供赋值运算符重载函数,则下面这条语句,只是进行简单的值拷贝,相当于浅拷贝。
若为CPerson提供了赋值运算符重载函数,则下面这条语句,会调用赋值运算符重载函数。

per1 = per2;
 

C++中的类型转换

1,const_cast
用于修改数据类型中的const或volatile属性,增加或者删除const或volatile
常量指针被转化成非常量指针,并且仍然指向原来的对象;

常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。 
const_cast<> 中必须是指针引用,或指向对象类型成员的指针

2,static_cast
(1)用于继承关系中父类和子类之间的引用或指针类型的转换
1) 向上类型转换,安全,自动
2) 向下类型转换,不安全,需要手动
(2)基本数据类型之间的转换,如int与char, enum和int,这种类型转换需要开发人员来保证安全。
(3)把空指针转换为目标类型的指针
(4)把任何指针类型转换为void *型。

3,dynamic_cast
(1)基类和子类之间的转换
(2)要转换的对象必须有虚函数
(3)如果转换是不安全的,则结果为NULL


4,reinterpret_cast
(1)转换的类型必须是一个指针,引用,算术类型,函数指针或者类的成员指针。
(2)从底层对数据进行重新解释,依赖具体的平台,可移植性差。
和C语言中的强制类型转换非常类似,不保证类型安全

5,C++标准类型转换总结
(1),const_cast<type> (expr); const_cast 运算符用于修改要转换类型的const/volatile属性。除了const/volatile属性之外,目标类型必须与源类型相同。这种类型的转换主要是用来操作所传对象的const属性,可以加上const属性,也可以去掉const属性。

(2)dynamic_cast<type> (expr); dynamic_cast在运行时执行转换,验证转换的有效性。如果转换未执行,则转换失败,表达式expr被判定为null。dynamic_cast执行动态转换时,type必须是类指针类型,那么expr也必须是一个指针,如果type是一个引用,那个expr也必须是一个引用。

(3)reinterpret_cast<type>(expr); reinterpret_cast运算符把某种指针改为其他类型的指针,它可以把一个指针转换为一个整数,也可以把一个整数转换为一个指针。

(4)static_cast<type>(expr); static_cast运算符执行非动态转换,没有运行时类型检查来保证转换的安全性。例如,可以把一个基类指针转换为派生类指针。
 

STL

和C++标准一起发布的,C++每发布一个版本,必定包含一个STL的版本。已经成为C++标准的一部分。

STL包含了数据结构和算法。

STL数据结构

容器类(数组,链表,哈希表)

顺序容器:数组, 链表

向量:vector,相当于数组,顺序的存储元素

[] : 可以通过下标来访问元素

Push_back : 在容器尾部添加一个元素。

Pop_back : 从容器尾部删除一个元素。

Insert : 通过迭代器指定的位置插入一个元素。

begin(): 返回一个容器内开始元素的地址

end(): 返回一个容器内结束元素后面的那个地址

​​​​​​​关联容器: 哈希表(map)

插入

map<string, CPerson>  map;

cPerson per(“abc”, 23);

std::pair<string, CPerson>  pair = std::make_pair(“abc”,  per);

map.insert(per);

map<string, CPerson>::iterator it;

it->first;   //string

it->second; //CPerson​​​​​​​

容器类的公共函数

注意:当容器的大小和元素的位置发生改变时,一定要对迭代器重新初始化。

size() : 返回容器中所存储元素的个数。

empty() : 判断容器是否为空

clear() : 清空容器中的所有元素

erase() :在容器中删除迭代器指定的某个元素

在容器中存入类对象时会重新构造一个新的类对象放入容器中。如果该类有拷贝构造函数就会调用这个拷贝构造函数。

​​​​​​​迭代器

用来遍历容器内元素的模板类,可以用迭代器来访问容器中的某一个元素。

通过  *<迭代器>  可修改实际所指向的内存数据

STL中的string

string 类的方法

string str = “aaabbbccc”;

const char * p = str.c_str()   //把string类转换为 const char *

int pos = Str.find(“bbb”); //返回”bbb”在string中的首地址索引

str.replace(str.begin(),str.end(), "aaabbbccc"); //字符口中替换

str.compare(""); //字符串比较,返回值为1, -1 0

string str2;

str2 = str1; //string对象直接互相赋值

智能指针

智能指针是一个模板类,是对普通的指针增加了一层封装,通过作用域和引用计数来管理指针的生命周期。

shared_ptr

shared_ptr通过一个静态变量的引用计数来维护指针对象的生命周期,把一个shared_ptr智能指针赋值给另一个shared_ptr指针时会增加shared_ptr的引用计数,或者把一个shared_ptr智能指针传递给函数参数时也会增加其引用计数。

当shared_ptr智能指针所在作用域结束时会递减其引用计数,当引用计数递减为0时,会调用类型参数对象的析构函数。

Shared_ptr中有一个指针,指向所引用的对象。

Shared_ptr类有一个静态的整型变量,来表示所指向对象的引用计数。

unique_ptr

是对所管理的指针是独占的,不能用于给其它unique_ptr赋值,它可以保证所管理指针的安全性。

多重继承

​​​​​​​重复继承

在多重继承关系中,例如基类为A,子类分别为B和C,若孙子D分别简单继承了B和C,这种继承就会造成数据的重复,导致有两个基类对象A,我们叫这种继承为重复继承。

​​​​​​​虚拟继承

子类在继承父类时在继承基类的类名前面加上关键字virtual,这种继承就是虚拟继承,在多重继承中虚拟继承中保证了父类对象在子类中只会有一份。

异常处理

异常处理的目的

让程序有机会和时间点来处理异常

跳过有异常代码,避免程序崩溃,继续执行异常代码后面的程序。

异常处理程序的结构,主要用三个关键字来实现:try , throw, catch

异常类型的匹配规则

C++中的异常是通过抛出异常对象(某种数据类型)而引发的,异常对象用于描述发生了什么样的异常,该对象的异常类型决定了应该由哪个与之匹配的catch块代码来处理该异常,如果没有找到与之匹配的catch块,则该异常没有被处理,那么就会引起程序崩溃。捕获到异常的处理代码是catch调用链中与该异常对象类型匹配且离抛出位置最近的哪个catch块

异常处理的匹配规则

当程序抛出异常时,会先暂停当前程序的执行,开始查找与之匹配的catch异常处理块。首先会检查异常发生的位置,定位哪一条语句产生了异常。如果异常产生的代码所属的try块的同一级上有与之匹配的catch块,则会去匹配该catch块,并进入该catch块处理异常。如果没有与之匹配的catch块,则退出当前函数的作用域,继续在上一级的catch列表中查找与之匹配的catch块。不断重复上述过程,直到查找到main函数中,如果没有找到与之匹配的catch块,则程序崩溃。或找到了则进入匹配的catch块处理异常,跳过了有异常的程序。

异常处理中的两个要点

匹配规则 :是通过在try作用域内抛出的异常数据类型与catch所要捕获的数据类型进行匹配。异常嵌套中的匹配规则:先从该抛出异常的try作用域在同一级的catch列表中匹配,如果没有匹配成功,则向上一级的catch列表进行匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值