C++学习笔记(一)

C++学习笔记(一),第1张

文章目录
  • cmake
  • 命名空间
  • 匿名命名空间
  • C与C++混合编程
  • 引用
  • 共用体
  • inline内联函数
    • 关于多次定义
    • class类初步了解
    • inline函数在c++中唯一一个多出来的特性
      • 这个特性的目的
  • c++中的NULL
    • C++中的NULL直接就是0
    • 函数重载时怎么解决
    • C++中引入了nullptr
      • NULL和nullptr的区别
      • nullptr的本质
        • C++的一个编译时的版本设置
      • nullptr的缺点
      • nullptr和void挺类似
  • 断言
    • 断言有点像内核的Kernel panic
    • 断言的使用场景
    • 静态断言
      • 静态断言在模板中的用处
      • 静态断言的缺点

cmake

cmake,按照它的语法描述,它可以自动生成makefile文件

命名空间

C++里面有一个命名空间的概念,就是说它那个namespace,他会把一个就是你的定义的一个变量,它是放到一个命名空间里面,也就是放到namespace里面,然后通过这样子去进行一个管理。这个是跟C语言不同的一个点,就是这个C++他有命名空间的概念,但是C语言没有这个命名空间,主要是用来干嘛的呢?它本质上设计来就是用来解决全局变量跟函数名重名的问题的,但是其实这个问题的话,C语言的本身也可以解决,但是解决的不够优雅,C语言,它解决的方法方法是他把一些函数名,全局变量啊,他在前面加一个前缀。

就比如说他在他定义的一个全局变量的前面加一个前缀,比如说他是一个串口的,那么他就加一个UART,然后一个下划线,什么什么什么意思?就是说,他是通过这种前加前缀的方式去区分不同的变量,但是这个方法的话,在小规模的C代码里面是可以用的,但是如果代码一旦庞大起来,这个还是有点难度。而且主要是还是不够优雅,那么,C++他就通过命名空间解决了这个问题,就是你你的,你可以把你的变量放到一个命名空间里面,比如说它有不同的命名空间,那么这些不同的命名空间里面的变量,就算重名了也是没有问题的。

这个命名空间,本质上它归根结底,也是去改变了他的一个最底层的编译的时候的链接属性,比如说你把你在这个命名空间里面的变量,跟另外一个命名空间里面的变量,它的链接的时候,链接的时候是不一样的意思,就是说他本质上改变的还是他链接的那个底层的一个链接的区别,这个其实也跟C是没有太大区别的,只不过C++他多了一个。命名空间的概念之后,他就这样就比较处理的就比较,方便一点,对就是你有一个命名空间之后呢,就是你这个命名空间里面的东西跟另外一个命名空间东西是相同的,也是可以的,因为最后链接的时候,他们不是链接在一块,就不会出现重名。

其实函数名跟全局变量重名的这个问题是比较严重的一个问题,因为因为最终他不管是C还是C++,他们最终都是要编译链接的,它编译链接的话,就根据这个函数名或者全局变量去找到那个东西去链接起来,所以当你的函数名跟全局变量名重名的时候呢,它链接的时候就不知道怎么链接了,所以说就是函数名跟全局变量重名的问题是一个。比较麻烦的问题必须要去解决,C的话,它就是用一个加前缀的方式去解决,C++的话就更加优雅一点,它就用了一个命名空间去解决它。但是其实本质上面归根结底还是跟链接相关的,解决的根源就是在链接时候,它是不一样的。

C加了前缀,那么它链接的时候就发现它是两个不同的变量,是不是那么链接的时候就就会按照不同方式链接,然后你如果是C++,你把它的变量放到不同的命名空间,那么它的链接的方式也是不一样的,本质上归根结底还是在他的链接的方向上面做了一个改变,最终链接不同,这才解决这个问题。

匿名命名空间

C++的那个匿名命名空间跟那个C语言里面的全局变量的static的用法很相似,就是它那个匿名命名空间,本质上就是你用了之后,那么它这个文件里面的东西,你把它放到匿名命名空间里之后,那么其他文件就不能访问这个东西了,就是这么简单。

也就是说这个匿名命名空间它没有名字的,所以就是你如果在这个C++文件里面用了这个匿名命名空间,那么你在另外一个C++文件里面是不能访问这个匿名命名空间里面的一些东西的,这是跟C语言的全局变量的static,关键字是一样的,它是可以用来一个它有一个限制的功能的,他限制你其他文件去用这些东西。

所以匿名命名空间里面放的东西一般都是他这一个,就他目前所在的这个C++文件里面,它所要用到的一些,它所要用到一些只有他要用到的东西的,只有他这个里面才需要用到的一些变量啊,函数名啊,还有一些结构体啊,还有一些累啊,都放到这个匿名命名空间里面,意思就是说这个匿名命名空间里面放的东西,只用在这个文件里面用就行了,其他文件里面没有必要用,就是这样子,他用法就是这样用。

然后他跟C语言的那个全局变量的static还有点不同,就是C语言里面的全局变量的static,它只能是用来修饰函数,还有全局变量,但是呢,那个C++的匿名空间里面不仅可以放函数变量,还可以放一些结构体,还可以放一些类,就说他这些结构体这些类,这些类型,它放到匿名命名空间里面之后,也可以实现一个。框死的作用,限制的作用,不让其他文件可以用到,它就它比全局变量的static的一个不同,就是它扩展了一点,它还可以把那个结构体啊,然后那个类呀,放到命名,放到匿名命名空间里面去,然后作为一个限制。

从一个更高的一个角度上看,这个匿名命名空间,它体现了C++的一种优雅性,就是它不算是一个特例,它不会说是一个特别的一个情况,它是可以在逻辑上面是说的通的,因为你这个匿名命名空间,它本身就是没有,本身就是没有名字的,那么你既然没有名字了,从逻辑上来讲,那你在其他文件里面自然就找不到这个匿名命名空间了,是不是?所以说他并不是一个特例,所以它也是符合匿名,他也是符合正常的命名空间的一些逻辑的。

这种没有特例,很少特例的情况,就是说他一切都是有一个逻辑的,所以这就体现了C++的一种语言实现的优雅。

C与C++混合编程

C与C加加混合编程,首先有两点先要搞清楚,第一.c加加的那个编译器居家家里面,它定义了一个下划线,C plus plus,这个东西是一个C加加编译器里面定义的一个东西,这个东西会根据的C加加C加加的版本,然后不同而不同。比如说现在的版本是118版本的,或者是八九版本啊,或者是二零版本呢?那么这个c si plus,它的这个里面的这个符号的关,它的值就是不就是不一样的,第二点就是要理解C跟C加加的那个底层的最后的链接是怎么链接的,它其实都是这样子的。
就是不管如何,她最后都是会变成一个.o文件,就是它是先从点C和点C加加文件,通过那个预处理变成一个点AI文件,点文件再通过一个编译变成一个汇编文件,就点S文件,点es文件,再通过汇编就变成了点o文件,点文件就在通过链接就变成了可执行文件,然后C与C加加混合编程,他们的编译都是到了的不同,它都是相同的,就是到了最后,这个都是可以到那个点o那里的。
然后点o文件本质上就是一个静态库文件,可以理解为它就是点I文件,然后就是点o文件,这种就是一个库文件,就是类似一个库文件,如果想要把它变成静态库或者动态库,那就去定义一下,把它定义成点I静态库或者点,So动态库就行了。
然后C与C加加混合编程的难点就在于它这个C加加,它有一个函数名重在机制,就是说它的函数名是可以是相同的,然后它中通过预处理,通过那个汇编之后等等等等处理之后,它得到了那一个可执行文件嘛,它的函数名是可以重在的,但是C是不可以的。
就比如说同样都是定义了一个ad,然后嗯,然后里面传参传的是in te gen in te,然后如果用C的话,最后出来的那一个点o文件,把它嗯,反汇编得到那一个反汇编文件,那么它里面的那个关键字还是ad,但是如果用的是C加加,那么他通过得到一个点o。文件之后,把它通过反汇编得到的那一个文件反汇编文件,它里面就不是ad了,而是ad ii。也就是说,它在它的那一个C加加,它有一个函数名重载,它最后会对一个函数名进行一个重载,如果虽然的那个名函数名是爱,但是最后它通过这个机制,它就会变成ad ii。
所以说C跟C加加的混合编程,他是有一定的难度的,就是难度的本质原因就是在于这里。所以如果要解决这个问题,那就必须要加一个extensi,就是当用C用C的时候呢,就加一个extensi,在那个extensi的那个括号里面,那么他就按C的方式去编译,如果没有在括号里面,那就是按C加加的方式去编译。
所以别人一般写C的库文件的时候,都会在他那个定义的函数前面加一个F的si si plus,然后ix ten si,原因是什么?原因就是为了防止以后如果这个C库文件,万一后面要要跟C加加混合编程的时候,那么他的这个C的话,就可以通过ex ten si,然后去实现一个C跟C加加的一个混合编程。因为通过if define c下划线cplusplus这个这个cplusplus只有C加加的编译器才有,所以当出现了这个关键字,那么就说明要用excelc就要,这就要把这个里面的东西当成C的编译器编译方法去编译,就不用函数名,重在机制。
那个点I文件是预处理后得到的文件,然后点a文件才是那个静态链接库的文件。这两点有经常会搞混,就点I才是那个预处理的文,得到预处理之后得到的文件,点a才是那个静态链接库文件,然后点so是动态链接库文件。
C加加调用C的时候呢?其实很简单,只要的C的头文件里面都用了那个if define c plus plus,然后extend c,那么它C加加调用C就很容易,但是如果是C调用C加加的话,那就没那么容易了。所以必须要得到C加加的那个反馈编得出来的那个函数名,然后这样子才能够去调用C加加,就这样才能用C去调用调用C加加。

引用

C加加里面多了一个引用的概念,就是如果是要交换两个参数的字,之前的话在C语言里面是用一个指针嘛,传地址给他改改地址,但是C加加很奇怪的是,它竟然可以传参的时候,在那个传参那里写个N的符号,然后就不用传地址,不用传地址的情况下也可以改值。
那个引用其实就是关联,然后关联的话,就是可以理解为他是一个弱化版的指针,就是他弱化了指针的功能,但是呢,他却提高了安全性,它从何体现提高安全性呢,就是它每一个引用,也就是每一个关联,他只能绑定一次变量,它后面不能再换了,就比如说是in te n de a等于。B,那么这个时候呢,那那个B就跟那个a是绑定关联起来了,后面就不能再换了,也就是其实就是个七个别名,但是这个别名呢,它一次只能他只要定义了,那一直都只能是跟那个绑定了,不能换。
所以也就决定了在定义引用关联的时候,要在定义的同时就初始化了,不能够定义的时候没有初始化,第二部在初始化,这就是这是由于它一次只能它,这是由于它永远只能绑定跟一个变量进行绑定造成的。总之这个就是一个引用,C加加引用的关联,这是C加加里面一个嗯,一个独特特有的一个点。它是一个弱化版的指针,它的目的就是为了降低指针的,它虽然弱化了指针的功能,但是却提高了安全性,然后一般用这个引用关联的时候呢,它不是正常,不是说定义了之后用的就是不是正常的情况下,这样用的,这种情况一般都常见于在返回值中,或者是在函数传参的过程中用这个引用跟关联。
关于引用和那个cos的关系,如果直接这样子cost,然后N的a等于B,然后这个时候呢,它其实就是的,如果用它引用的那个别名去改的话,改不了她的值,但是如果用它本来的那个变量,是可以改它的值的,这样子一看,似乎觉得他那个没有什么用处,但其实这个的用处是。不是这么用的,它是放到那个函数传参里面去用的,就是说当这个变量,为了安全起见,不想改它里面的值,那么就可以用这个方式,然后到了那个函数传参的时候,引用的时候呢,加一个cost,那么它就不会改到里面的值了。
这个关联的引用虽然是指针的弱化版,但是它跟指针完全不一样,就这个引用的话,它指的还是它那个,指它的size of,还是那个数据类型的大小,但是指针的话,它的size of就是那个指针地址的大小,永远都是四个字节,但是这个引用的话呢,它就是那个变量来的,它跟指针完全不一样,它没有地址的概念,它所以它还是那个数据类型的值,就比如说是double类型的,那它就是八个字节。

共用体

关于西加加的一个共用体,它的这个共用体,它有一个匿名的,一个竖一个特性,它的这个特性的主要来由就是有一些时候呢,他们懒得给这个供体起各类型了,直接就给它起个变量名了,这样的话也就说他只用一次,不用多几次了,我干脆这个供体我就只用一次,所以我干脆就只定义这个,就叫这个变量,那就可以把这个类型给省略掉了,就我不会再教他另外一个名字了,他就是也不会再用这个类型去多定义,另外一个变量,那么我就直接把这类型省了,直接就给他一个变量,就这样子,用他的变量就行了。

inline内联函数

关于inline内联函数,一般他是放到头文件里面的,他因为他在预处理的时候,他是原地展开的,它就很像那个井号提发音的那个预处理那种方式,所以他应该是放到宏定义里面啊,所以他也是放到那个头文件里面。还有就是它放到头文件里面之后,他就不用声明了,你在为头文件是在最前面的,你在一个函数这样一写,所以他这最前面,所以他就没必要声明了,所以就可以省去声明的这个步骤,所以这两点就决定了应该放到头文件里面去。

其实在C语言的时候就已经说你是online,内联函数,其实它很大程度上就等于是一个宏定义来的,它就是原地展开的,有一些函数,它也是用宏定义的方式去实现的,但是为什么要有内联函数呢?就是内联函数,它比宏定义多了一个参数类型校验,它可以进行一个参数类型的一个校验,这样校验之后就可以使用,就可以嗯,有一个多的一个,这样一个参数类型校验,它比宏定义。

之前在C语言里面没有讲的这么细过,因为函数它是可以被多次定义的,就是说他可以多次定义,为什么呢?因为它它相当于一个红来的,他在预处理的时候,它就把它有一个函数给展开了,展开到函数里面去了,所以当它展开到函数里面去的时候呢,所以他这个函数本身就已经不存在了,他已经展开进去了,跟红一样。所以你这个东西,你这个内涵是可以重复定义了,因为你每定他就,他就展开了,就放到里面去了,他就这个函数就消失了,因为没有了,那肯定可以重复定义。

关于多次定义

注意,这里指的多次定义,重复定义,它的意思是说,你定义时候它的里面的参数啊,那那参数体校要是一样的,不是说你在在那里定义的是这样,现在那里定义就是那样,这叫这就不要重复多次定义了,这个样子就就是不行的。你只能说在不同地方可以重复的去定义它,定义这定义里面的参数类型是相同的,不能不一样。

但是一般的话不建议重复定义,因为你重复定义之后你改,那你如果真的要有有一天你要改它,这个内敛函数或者是宏的话,你要改很多地方,所以你每一个定义到的地方都要改,所以这很不方便,所以最好的方法就直接用红,不不不不,所以最好方法就直接放到头文件,改头文件就行了。

但是这个多次重复定义啊,他从原则上来讲,他并没有重复占用内存,就他在占内存方面并不会造成影响,因为它最后都是要原地展开的,不存在说你多定义了一个,就多占了一个内存,它不建议重复定义的原因并不是因为占内存,也而是因为他你在维护代码,然后就是在管理代码的时候不方便,你要改的话,要找到他所有的你定义过的地方去改,这样就很不方便,所以要放到头文件是这个原因。

注意这个,原地展开,这个那个,还说原地展开它,你只是对编译器的建议而已吧,就是你是建议编译器在原地展开,但是最终能不能原地展开还是要看编译器,它自己有一时候,有些时候它是并不能原地展开的,编译器还是会把它当成函数正常函数去用的。

class类初步了解

Si家家里面的class类,它其实本质上来讲是一个简易版的一个structure,就是他C加加,他喜欢做一些封装吗?那些东西就跟之前的引用一样,所以其实class这个类呢,也是从struck的过来的,所以就是他跟stride一个唯一的区别就是struck里面的只能放函数指针,它不能放函数进去,但是class它已经可以把函数也能放进去了。但是这个的话,其实本质上来讲,这class类,它本质上里面的函数,本质上还是通过struck那个函数指针去实现的,只不过C加加帮我们做了一层,做了一做,多做了一步,所以就变得比较简易了一点。实际上这class就是从struck的演变过来的,它本质上还是一个struck的类,它是一个简易版的一个structure。

所以总结一句话,就是说class这个类,它是由struck演变过来的,它本质上就是一个struck类,只不过C加加帮你做了一些简化,使得这个class类它里面可以直接放函数了,而不是只用放函数指针,不不是,而不是,只能像struck的那种类,一样是struck,那样子只能放函数指针了。

一个正规的类的写法,正常的类的写法就是你要把函数的声明写到类里面去,然后你把函数的定义写到外面去。

然后这个类配合上那个line的话,就说你如果要在类里面用line的话,你在函数这个类外面的函数的一个定义里面,要写online,在那个类里面那个函数的声明也要写inline,但是其实从后面的话,你可以在那个类里面的online把那online省略掉,但是函数定义那里的online是不能省略的。

这音量函数呢,它有个特点,就是你如果要是在一个C文件里面定义了的话,它就只能在那个C文件里面去使用了,它跟红是一样的,你所以你如果不把它放到头文件里面,你把它放到C文件里面的话,它就只能在它放到那个C文件里面去使用的。

inline函数在c++中唯一一个多出来的特性

依赖函数在C加加中的多维一多一个特性就是就是C加加里面啊,它的类里面是可以写函数的本体的,就是正常来讲的话,应该是只放一个函数声明就行了,然后,然后他C加加编译器肯定会在编译器阶段把它转化成指针啊,不转化成函数指针,但是你如果是在这个类里面呢,放一个函数的一个定义,有函数体的话,虽然很奇怪,但是其实编译器也是可以做的。就是编译器,它也会把你这个函数体定义的,这函数体,它也会去找到一个它的函数指针去执行它,这样也是可以做的。然后它跟in line的关联,就是,如果你一旦把这个函数体函数的定义放到了类里面的话,那么它就默认它是一个内联函数了,就是一个in line函数了,这个时候你就算不加inline关键字,它也是online函数,所以这时候online是可以省略掉的。

这个特性的目的

Si加加他为什么要这么设计,其实本质上也是为了提高它的简便性跟效率,因为它这个本质上来讲,它就是深度绑定的嘞,因为这个函数跟这个类就是深度绑定了的,你这种情况下,你何必不加inline,这何必不用依赖呢?所以他应该就是用依赖的,所以这就是省去了我们的一些麻烦,就是他已经是本质上本身就深度绑定了,那就是依赖吗?是吧,如果你没有这个规则的话。那么你就要把你的那个类,还有你的那个银赖函数,再写在外面的那个依赖函数都要放到那个头文件里面去,然后你这就挺麻烦的,你后面的话调调调起代码来是有一定的麻烦。所以就是从一个代码的开发的性开发方便性来说,他这么搞的话,是本身是深度绑定的,你这么一做,那就是非常的切合。

也就是说,你如果是把它的内联函数放到这个类的外面,其实你在用的时候呢,你这两个都是要一直放到一起的,要一起放到同个头文件里面的,不然的话那类找不到那函数嘛,是吧,但是你这么一想到,它既然一直都放一起,那还不如那C加加编译器就想还不如就把它干脆就缩进那个类里面去,这样写代码多方便,少写了多少,写了几行,所以本质上是这这样除法的设计的。

c++中的NULL

C和C++里面的NULL是不一样的,C里面的NULL,它本质上是一个(void *)0,比如说你定义了一个

int *p = NULL;

那么他这个NULL,他用宏展开之后就变成了(void *) 0,它在C语言里面是可以的,这个(void *)0它会隐式转换成int,到时候它会转换成int *的,但是C++里面呢,它不行,为什么他无法这样子。把这个(void *)隐式转换成int *,因为C++它的类型的检验比C还要强,因为C++它的复杂程度比C高了一点,它就更容易触发一些稀奇古怪的错误,所以它在这里就更加要注意,它不允许你有这这样一个程度的自由度,所以它为了一个保证安全,就必须得要把这个禁掉,就不允许这样子用。

C++中的NULL直接就是0

C++里面他直接NULL就是个零了,所以int *p等于0,但是这也很奇怪,它也没有强制类型转换了,按理说你C++如果是一个强类型的话,你这不是也不行,但就是可以,他就是你把那定义成零了,那就是他可以,他这种情况下,它就可以把它这个零隐式转换成int*,就是这样子,你如果单单纯把它定义成那等于零,它可以隐式转换。

函数重载时怎么解决

在C++里面,它是允许函数重载的,函数重载的意思就是说,他有可能有两个函数,它的函数名是一样的,但是它里面传的参数是不一样的。然后你在用的时候,它C++就会是,就是看你到时候用了这个函数名里面,你传的参是什么,然后去找它对应的函数。比如说一个传参是普通变量,另一个函数传的参数是指针变量,但他名字是相同的,那你在用的时候呢,你如果传的是一个指针,那么他就会找到那个传指针的那个函数名。如果你用的是一个传变量,那他就找到传变量那个东西,那个函数,函数名是一样的,这就叫做函数重载,它本质上还是刚刚还之前说了C跟C++混合,编程里面它有一个预处理,C++的预处理,它会把它的函数的那个传参,比如说它是int int,它就会变成ii,所以它两个函数,其实本质上在预处理里面已经变得不一样了。

所以说函数从在本质上还是预处理的时候,C++在预处理的时候,它把这函数名也变了。所以本质上讲,这函数你就算写的时候是一样的,但它在预处理的时候,它已经函数名是不一样的。

C++里面,他这个NULL这么定义,它有一个问题,就是在那个函数重载的时候,比如说你这函数重载,你的第一个是第一个传的参数是int类型,第二个传的参是那个int *类型,那你最后你再调用这个函数的时候,你给他传个NULL,那他到底是int类型还是int *类型呢,所以C++在这个时候呢,他为了避免引起歧意,他就在这里,就选择了报错,就不让你这么做。

C++中引入了nullptr

然后C加加为了避免这种歧义,他就发明了nullptr,你用这个的话他就不报错了,你用这个他就默认你这个用的是指针了,那你就是函数重载的时候呢,他就是用传的是指针的那一个函数。

NULL和nullptr的区别

这个nullptr的话,他跟NULL一个区别就是NULL,他是一个宏来的,但是nullptr是一个关键字来着,它就是发明了一个空指针给你用。

所以其实在C++里面的话,你定义一个指针,然后让它指向空的时候,那就不应该不应该是用NULL,而是用nullptr,比如说char *p等于nullptr,而不是做成NULL,因为他是在C++里面,NULL是一个宏,他直接就是个数字零,这是不对的,虽然他不报错,但是也是不太恰当了,因为他那是零,然后char *p的话,它是指针。虽然C++里面它是可以允许你这样编译通过的,但是其中严格上来说,你应该是用用C++里面它给你的关键字nullptr。nullptr就是C++里面为了解除歧义,然后专门发明了一个关键字。

nullptr的本质

这个nullptr的本质是一个类来的,就是你定义出来的一个类,它这个类里面呢,有一个在里面它会返回一个零,然后它重载呢,是把它变成了一个指针,所以说这个nullptr的本质就是你定义了一个类,然后这个类,它的类型是指针类型的。

const class nullptr_t
{
    public:
        template<class T> inline operator T*()const {return 0;}
        template<class C, class T> inline operator T C::*() const {return 0;}
    private:
        void operator&() const;
} nullptr={};
C++的一个编译时的版本设置

在C加加里面,你去进行编译的时候,你可以选择你要编译的版本,就是说你在后面加STD等于什么什么,比如说你要九九版本的STD99,或是STD等于一三呐,你用一三版本之类的,就是说他C加加可以按不同版本去编译的,按你需要的版本去编译,你就后面加STD等于什么就行了,编译的时候。

nullptr的缺点

其实这个nullptr它没有解决掉实质的问题,它说可以解决那个变量跟指针变量的一个重载的一个冲突问题,但是如果它的函数重载两个都是指针的,那这样的话,它nullptr也是无法解决的,就是说它两个指针nullptr也不知道你重载的是哪一个。

nullptr和void挺类似

其实这个nullptr他有点和void相似,因为他你看我们之前在C里面用的是void *,它可以是任意的一个数据类型,都可以,他到时候根据选择去做,然后这个nullptr的话,它其实也是跟void很相似,他都可以支持,就是你是哪一种类型都可以,到时候我都可以支持,你到时候是哪一个,nullptr就变成哪一个。

断言

断言这个东西就是他。他不是在编译时出错,它是运行时你程序编译是成功的。你运行的时候,只要你运行的过程中一旦触发了这个断言,那你程序那里去就停止了。就是这个意思。

断言有点像内核的Kernel panic

断言有点像那个C源里面,内核里面那个kernel panic那个kernel panic就是你一旦遇到了,就直接运行的时候,就就就在那里断掉,就是这样子就停止。

这个断言的使用场景其实也是跟Linux内核的kernel panic一样的,你用它,那就代表你这个东西是你无法接受的一个错误了,一定要在这里卡住了,终止掉了才用断言。比如说你在打开一个文件系统文件的时候,你你一般情况下用不上断言,就比如说你这个文件没有打开成功,你返回一个那,那么你就可以用衣服闹一幅他。等于闹,那么你就反,你就打印一个什么error或者是一个重新来一次,重新做一次打开,是吧,就是你会有一些其他系列的 *** 作可以弥补,如果你在这里直接写了一个断言的话,那程序你就是,就是认为你是认为这个是很严重的事情啊,就直接就把这个程序在这里就终止掉了,所以断言一般是这个比较紧急情况下,你认为紧急才用的。

断言的使用场景

这个断言呢,一般用在什么场景呢?就是用来解,就是用在你文件的最开头,你这个代码最开头,你传参传进来之后,他传参是否是正确的,一旦传参都不正确,你就只用断言了,你就直接就是开头就断言掉,它就终止掉,一般都是在这里用,就在函数开头传参的时候用。

静态断言

这个C语言里面的断言他是在运行时报错,但是其实运行时报错是不太理想啊,最好的情况就是你在编译时就报错了,所以C加加里面它就引入了一个静态断言的这样一个东西,就是你这个静态断言就是一个家一个static下划线,再来一个assert,然后这个静态断言C加加里面静态断言的使用就是你用这个static,下划线assert,然后括号。里面写上你要判断的表达式,然后后面写上你要出报错的一个打印出来的东西,你写上这个之后呢,一旦你的表达式里面的那个不符合条件,那么他就会打印出它,在编译的时候就可以打印出错误了。他跟C语言就的断言不一样,它编译时就可以打印出错误了。

静态断言在模板中的用处

然后这个C加加里面的静态断言,我们在平常用的地方比较少,因为没有这个必要,我们直接,因为我们都一般都知道吗,比如说他,你他一般是用来做一些校验的吗?我们一般肉眼都可以看出来他到底对不对,是不是,所以一般用不到,所以他这个用的最多的C加加的静态断言用的最多的地方是在他模板那里,因为他C加加的模板里面,他的一些函数类型是比较模糊的,你不知,你很很难去判断他这个函数它的传的参数到底是什么类型,模式很模糊的,所以这个时候你就需要有一个静态断言去用它。

这里静态断言就是用来,就是一般是那些写模板的人,而不是用模板的人去做的。就是那些写模板的人,他本身自己是清楚的,他是怕你那些用模板的人,他可能没那么熟悉,所以他写模板的时候就提前预想到可能会有问题,就帮你在那里写,加了一个静态断言,然后你你到时候你用模板的那些人呢,那么你就可以哦,有个静态断言在那里,你就可以大概知道错哪里,否则你连静态断言都没有的话,你用模板,那些人一旦运行时候出错,你很难查找出问题所在的。

静态断言的缺点

但是这一个C加加里面的静态断言他有个不好的地方,就是它打印出来的报错,它其实是很抽象的,就是没有那么明确的,你可能最多就只能知道他那里有一个静态断言打印出来出错了,但是你可能并不知道他,你不能通过他的文字信息得到它到底是什么问题的,什么类型的错误,然后这个静态断言他是C加加11里面出现的,它的C加加11里面出现的一个问题,就是这个问题,就是他打印的那个信息,很难,通过这个信息去判断出它是什么类型的错误。然后到了C加加20,然后它又有多一个关键字叫concept concept concept concept,就是你可以理解为就是那个静态断言的一个进一步的一个版本,它的话打印出来的信息可能就比静态断言更好理解一点,就是这样子。

总的来说,这个嗯,静态断言,它主要就是用去后面的模板的一些他的模板里面的一些参数,它的是否是常规合理的,你因为你模板那里不不清晰的,所以你可能一些参数的一些东西不是太合理的,所以你要通过一个静态断言你开发模板的人,你要写模板的时候,给他一个静态断言进去,用模板的人才能够大概清楚至少有一个方向在那里,至少至少知道他这里是错的,但是什么清清不清楚,是什么类型错,他文字信息是很难够推断出来的,但是至少知道有个错。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1324324.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-12
下一篇2022-06-12

发表评论

登录后才能评论

评论列表(0条)

    保存