Linux/C++系统编程 day3

C++应用方向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-We35Q0DJ-1610347051024)(\image-20210104100841690.png)]

  • C++头文件都是模板编写,没有.h,而模板有一个特点必须知道所有实现之后才能进行正常编译

    (cd /usr/include/c++)

  • 函数声明和定义

    (形式上区别,花括号和末尾分号

    声明可以有多次,定义只能有一次)

  • <<输出流运算符,左移乘2 endl换行

  • >>输入流运算符,右移除2

  • 同窗口无法编译运行

  • vimplus中可使用gcc注释一行,u还原或者再按一次

  • 运算符重载,视作函数

命名空间

为什么要使用命名空间?

  • 解决函数命名冲突
    (命名冲突是指同一个作用域内有多个同名实体)

命名空间是什么?

  • namespace 名字{ }
    (末尾不用加分号,其中可以定义变量、常量、函数、结构体、类、模板、命名空间,统称为实体)

如何使用命名空间?

用法1 :using编译指令

  • using namespace std;

    (可以一次将std命名空间中实体全部引出,可能导致自己定义的实体和std中实体冲突)

用法2 :作用域限定符

  • wd::

    (每次使用实体时加上,即使自定义的实体与std命名空间中的实体冲突也没问题,但使用起来麻烦)

  • ::

    (匿名命名空间,如只有一个printf不需要加作用域限定符也可以正确使用)

用法3 :using声明机制

  • using std::cout

    (一次只将命名空间中的一个实体引出,自然写代码时就不会定义同名函数)

两个命名空间内互相调用

  • type wd::func()

    (带命名空间的函数声明,结构体不能这样使用)

  • 命名空间可以扩展,先写一部分,中间被隔开,后写一部分

    (包括标准命名空间,一般std里是小写,但不建议)

命名空间的嵌套

  • wd::wh::

    (在一个命名空间中再定义另一个命名空间,调用内部实体时要写全作用域)

const常量

  • 可以创建常量,定义时必须初始化,不能进行二次赋值

用法1:修饰变量

  • #define MAX 10

    (宏定义,发生的时机在预处理阶段,做字符串替换,不做任何类型检查,若产生bug直到运行时才出现)

  • const

    (发生的时机在编译阶段,会执行类型检查,若产生bug会立即报告)

    • const int number=10;

    • int const number=10;

      (以上两种都可)

用法2:修饰指针

  • 关于指针,我们只关注其本身和所指的内容

  • 修饰谁谁就不能变,双重const则都不能变

  • 优先级:()>[]>*

常量指针

  • const int * number=10;

  • int const * number=10;

    (当const位于*左边的时候,不能改变指针所指的值,但是可以改变指针本身指向)

指针常量

  • int * const number=10;

    (当const位于*右边的时候,不能改变指针本身指向,但是可以改变指针所指的值)

函数指针与指针函数

  • int (*pf)(int x)

    (指向返回类型是int,参数是int的函数)

  • int* pf (int x)

    (函数的返回类型是指针,参数是int)

数组指针与指针数组

  • int (*parray)[]

    (指向含有[]多个元素的一维数组,二维数组时也叫行指针)

  • int* parray[]

    (数组里面都是指针,可以用来存放变量地址,需要分别赋值)

用法3:对成员函数的修饰

  • 见类

用法4:对对象的修饰

  • 见类

开辟和回收堆空间

C中空间的使用malloc/free表达式

步骤1:申请堆空间

  • int *pInt = (int *)malloc(sizeof(int));

    (严格来说应该判断是否申请成功,即是否空指针)

步骤2:清零(初始化)

  • memset(pInt,0,sizeof(int));

    (sizeof是运算符)

步骤3:赋值使用

  • *pInt=10;

步骤4:回收(释放)堆空间

  • free(pInt);

    (打印地址时printf中用%p)

C++中空间的使用new/delete表达式

步骤1:申请堆空间并初始化,赋值

  • int *pInt = new int(10);

  • int *parray = new int[10]();

    (对于数组此处不可以赋值)

步骤2:回收堆空间

  • delete pInt;

  • delete [] parray;

    (中括号中间不能填数字,以免被视为偏移,在开辟空间时已经默认多开了4个字节来存数组长度、标志位之类的信息)

  • size_t 类型表示C 中任何对象所能达到的最大长度。它是无符号整数

两者的区别与联系

  • malloc/free是C中的库函数,而new/delete是C++的关键字

  • malloc只能申请原始的堆空间,new申请堆空间并进行( )初始化

  • 都是用来申请堆空间

  • 都要成对使用,否则会造成内存泄漏

    • 内存泄漏:分配了内存而没有释放,逐渐耗尽内存资源,导致系统崩溃

    • 内存越界:向系统申请一块内存,使用的时候超出了申请的范围

    • 内存踩踏:也叫内存重叠,一般是在拷贝过程中目的地址范围和源地址范围有重叠导致的。

    • 内存溢出:想要分配的内存超出了系统能够提供的

    • 野指针:指向被释放的或者访问受限内存的指针

&引用

  • int number=10;

    int &ref=number;

    (已定义变量的别名,引用的提出就是为了减少指针的使用)

实质

  • int *cosnt

    (指针常量)

  • 引用定义时必须初始化,一经绑定就不能改变指向

  • 操作引用与操作变量本身是一样的

  • &跟了类型的是引用,否则是取地址

  • const int &a=10;

    (当既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变时,就应该使用常引用)

用法1:作为函数参数

  • 引用传递和指针传递不同于值传递,它们不需要进行复制,而值传递的形参只是实参的一个副本

  • 引用传递相比于其他两个不会额外占用栈空间,

用法2:作为函数返回类型

  • 可以对函数返回值赋值

  • 函数返回引用的前提是实体的生命周期大于函数的生命周期

  • 不要返回局部变量的引用,其生命周期在函数调用完时已结束

  • 返回堆空间的引用,可能有内存泄漏的隐患(new/delete未成对出现),除非有内存回收的机制

    • 可使用引用绑定函数int &ref=func();

    • 之后再delete &ref;

      (语义无错,但是不推荐这种写法)

指针和引用的区别与联系

相同点:

  • 都是地址的概念;
    (指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名)

区别:

  • 指针是一个实体,而引用仅是个别名;

  • 引用使用时无需解引用(*),指针需要解引用;

  • 引用只能在定义时被初始化一次,之后不可变;指针可变;

  • 引用没有 const,指针有 const;

  • 引用不能为空,指针可以为空;

  • “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;

  • 指针和引用的自增(++)运算意义不一样;

  • 从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。

强制转换

  • (tye) a;

    上面是C的写法,C操作简单,但C++更加安全

用法1:static_cast<type>(a)

  • 适用范围:

    • 基本数据类型之间

    • void指针转换为目标类型指针,但不安全

    • 任何类型转换为void

    • 用于基类和子类之间指针或引用的转换

      (进行上行转换(把子类的指针或引用转换成
      基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类
      型检查,所以是不安全的。)

  • grep -rEn “*_cast” ./

    (可以查看是否使用强制转换)

int inumber=10;
float fnumber=12.34;
inumber=(int)fnumber;//C
inumber=int(fnumber);//C++
inumber=static_cast<int> (fnumber);//C++

void *pre1=malloc(sizeof(int));
int *pre2=static_cast<int*>(pre1);//C++
delete pre2;
pre2=NULL;//指针置空

用法2:const_cast<type>()

  • 去掉常量属性,将常量指针转化为非常量指针
const int num=100;
int *p2=const_cast<int*>(&num);
*p2=200;//C++未定义的行为

用法3:dynamic_cast<type>()

  • 用于基类和派生类之间的转换,尤其是下行

用法4:reinterpret_cast<type>()

  • 用于处理无关类型之间的转换,容易导致程序不安全
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值