🥝 运算符
type
status
date
slug
summary
tags
category
icon
password
Property
 
🥝

 

左值和右值

C++中左值和右值概念是从C中继承过来的,C定义的很简单,在赋值语句左边的是左值,右边的就是右值。
C++中的比较复杂,C++的左值表达式的求值结果是对象或函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对像。此外,虽然某些表达式的求值结果是对象,但它们是右值而非左值。通常来说,右值使用的是对象的值(内容),左值使用的对象地址(内存中的位置)
 
不同运算符对运算对象的要求各不相同,有的要求左值、有的要求右值;返回值也有差异,有的作为左值返回,有的作为右值返回。一个重要的原则是:在需要右值的地方可以用左值来代替,但是不能把右值当成左值(位置)使用。当一个左值被当成右值使用时,实际使用的是它的内容(值)。
 
🥝 类型转换
type
status
date
slug
summary
tags
category
icon
password
Property
🥝

C++ 中的类型之间存在转换时被认为是类型相关,当需要其中一种类型值时,可以用另一种类型值替换。
  1. 隐式类型转化(截断或提升):编译器在编译阶段自动进行,能转就转,不能转就编译失败
  1. 显式类型转化(强转):需要用户自己处理
 

隐式转换

以下情况将发生隐式转换:
  • 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型
  • 在条件部分,非bool值将首先转为 bool
🥝 简单语句和作用域
type
status
date
slug
summary
tags
category
icon
password
Property
 
C++中的大多数语句都以分号结束,一个表达式加上; 就变成了表达式语句
如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,则应该使用空语句,空语句中只含有一个单独的分号 ;
 
空语句是一条语句,可用在任何允许使用语句的地方:
 
 
复合语句是指用花括号括起来的(可能为空)语句和声明的序列,也叫做,一个块就是一个作用域,在块中引入的名字只能在块内部以及嵌套在块中的子块里访问。通常,名字在有限的区域内可见,该区域从名字定义处开始,到名字所在(最内层)块的结尾处为止。
如果在程序的某个地方,语法上需要一条语句,但是逻辑上需要多条语句,则应该使用复合语句。把要执行的语句用花括号括起来, 就将其转换成了一条复合语句。
🥝 控制语句
type
status
date
slug
summary
tags
category
icon
password
Property
 

 

条件语句

if语句

if语句的形式:
 
if-else语句的形式:
🫒 函数基础
type
status
date
slug
summary
tags
category
icon
password
Property
 
🫒

 
一个典型的函数定义包括:返回类型函数名、由0个或多个形式参数(parameter,形参)组成的列表函数体。函数执行的操作在语句块中说明,称为函数体。
notion image
 

编写函数

的阶乘是从1到所有数字的乘积:
🫒 函数参数
type
status
date
slug
summary
tags
category
icon
password
Property
 
🫒
目录

 
每次调用函数时都会重新创建它的形参,并用传入的实参对形参进行初始化。形参初始化的机理与变量初始化一样。
形参的类型决定了形参和实参交互的方式:
  • 当形参是引用类型时,称它对应的实参被引用传递或者函数被传引用调用。和其他引用一样,引用形参也是它绑定的对象的别名;也就是说,引用形参是它对应的实参的别名
  • 当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象,称这样的实参被值传递或者函数被传值调用
 
如果形参不是引用类型,则函数对形参做的所有操作都不会影响实参
🫒 返回类型和return
type
status
date
slug
summary
tags
category
icon
password
Property
 
🫒
目录

 
return 语句将终止函数的执行并返回控制权到函数调用点,将立即执行调用点之后的代码,这个地方叫做返回地址,返回地址在执行调用时被保存在调用栈上。C++return语句返回一个返回值给调用者,而一些语言则没有提供返回值的语言特性,它们转而提供了出参数,还有另外一些语言则默认函数的最后一条语句是函数的返回值。
当函数执行到最后一条语句时会自动返回。曾经有争议是否应当在函数的中间返回(称为早期退出 “early exit”),支持的观点有证据显示从中间返回使得程序员书写起来更不易出错,也更容易理解。而反对观点则认为中间返回将导致资源得不到有效释放,而从函数的底部退出就不会跳过释放的代码。
 
C++ 通过在栈展开时由对象释放的析构函数自动调用进行资源释放,这种方式也被称为RAII(resource acquisition is initialization)资源获取即初始化,很多人认为这是一个非常糟糕的术语,认为应当用DIRR(Destruction is Resource Relinquishment)析构即资源释放,或者叫 SBRM(Scope Bound Resource Management)局部绑定资源管理。
 
有两种形式进行函数返回:
🫒 函数重载和匹配
type
status
date
slug
summary
tags
category
icon
password
Property
 
🫒

 

函数重载

函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数,main函数不能重载。
这些函数接受的形参类型不一样, 但是执行的操作类似。调用这些函数时, 编译器根据传递的实参类型推断想要的是哪个函数:
函数的名字仅仅是让编译器知道它调用的是哪个函数,函数重载可在一定程度上减轻起名字的负担。
🫒 内联函数和constexpr函数
type
status
date
slug
summary
tags
category
icon
password
Property
 

内联函数

C语言觉得一个小函数重复调用函数栈帧,函数栈帧中保存一些寄存器,之后又销毁,这些都是有消耗的,所以C语言引入#define宏
 
宏的优点:增强代码复用性,提高性能
缺点:
  • 不方便调试(预编译阶段进行替换,调试的时候看不到)
  • 代码可读性差,维护差,容易误用
  • 没有类型的检查(单纯替换不会报错,但是错误)
 
🫒 函数指针
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
要想声明一个可以指向某种函数的指针,只需要用指针替换函数名称即可:
 
*pf两端的括号必不可少!如果不写括号,则 pf是一个返回值为 bool指针的函数:
 
可以直接使用指向函数的指针来调用函数,无须提前解引用指针。
 
对于重载函数,上下文必须清晰地界定到底应该选用了哪个函数,编译器通过指针类型决定函数版本,指针类型必须与重载函数中的某一个精确匹配。
🫒 辅助Debugging
type
status
date
slug
summary
tags
category
icon
password
Property
 
程序包含用于调试部分的代码,这部分代码只在开发程序时使用。当应用程序发布时,屏蔽调试代码。这种方法用到两项预处理功能:assertNDEBUG
 

assert预处理宏

C++沿用了C中使用assert宏来断言某些不可能的状态,当assert中表达式求值结果为false将导致程序打印错误信息并退出。使用 assert宏的文件不能再定义名为assert的函数、变量,否则将会被认为是assert宏,因为,宏替换发生在编译器编译之前。
  • assert宏定义在cassert头文件中,宏定义的名字由预处理器处理,而不是编译器。因此可以直接使用assert,而不是std::assert。和预处理变量一样,宏定义的名字必须在程序内唯一。
  • assert常用于检查,程序中"不可能发生的"条件。
 
assert宏的行为只有在没有定义宏NDEBUG时才会执行,可以通过在编译时提供编译选项-D NDEBUG来禁用掉assert宏的执行。通常,在开发时定义assert,在生产上线时关闭assert
🥥 类&对象
type
status
date
slug
summary
tags
category
icon
password
Property
🥥

 
类的基本思想是数据抽象(data abstraction)封装(encapsulation)
  • 数据抽象是一种依赖于接口(interface)实现(implementation) 分离的编程及设计技术。类的接口包括用户所能执行的操作;类的实现包括类的数据成员、负责接口实现的函数体以及其他私有函数。
  • 封装实现了类的接口和实现的分离。封装后的类隐藏了它的实现细节,也就是说,类的用户只能使用接口而无法访问实现部分。
类要想实现数据抽象和封装,需要首先定义一个抽象数据类型。在抽象数据类型中,由类的设计者负责考虑类的实现过程;使用该类的程序员则只需要抽象地思考类型做了什么,而无须了解类型的工作细节。
 

C++类定义