数据类型决定了:数据形式和数据操作
C++主要有void和算术类型(字符、整型、布尔值、浮点数)
数据类型大小以微软实现为例:
C++ 类型系统 | Microsoft Learn
下面是cppreference提到的数据类型大小,覆盖更全:
部分数据类型的取值范围:
赋值与算术类型不一致时,有以下自动转换规则:
未定义行为(Undefined Behavior)又简称UB,在C++里指的是编译器不检测或无法预知或与运行环境相关的行为,这种行为是C++为优化性能且信任程序员产生的历史遗留问题,检测其本身比运行成本更高。不应该也不能通过UB实现程序目的
不要混用有符号和无符号数,有符号数会自动转换成无符号数(避免溢出)
补充一下负数的取模运算:(-1)%256 = (-1+256)%256=255%256=255
字符串字面值其实是常亮字符构成的数组,结尾会加上'\0'
C++赋值和初始化的区别 - 掘金
这里总结比较详细,概括讲就是初始化是变量创建的时候给初始值,赋值是擦去原有值再重写的过程,如果涉及对象的构造函数和赋值函数,体验会更明显
(插一嘴,其实如果硬要区分的话,C++不应该采用=作为初始化的形式之一,没办法,历史问题)
C++一般使用下面几种初始化方式
如书上举了四种例子:
默认初始化 - cppreference.com具体可以看这里的例程
定义与 ODR (单一定义规则) - cppreference.com
这里讲的比较详细,除了列出的一些情况之外都属于定义
简单概括就是声明只是让编译器知道了对象的类型和名字,定义才进行分配内存的工作(可能附带初始化),未定义的对象无法使用,因为没有分配内存(反过来说,能使用的都已经定义过了)
extern关键字可以用来分离声明和定义
C++作用域主要有:块作用域、函数形参作用域、命名空间作用域、类作用域、枚举作用域、模板形参作用域
作用域允许嵌套,内部名字可以覆盖外部同名对象,但不建议这么做
类型 - cppreference.com介绍了C++类型系统,这里主要是复合类型中的指针和引用,后续会介绍类、枚举、数组等
引用绑定而非复制对象,起到别名的作用,不必占用内存,本身也不是对象
(尽管编译器实现时会或多或少根据情况分配内存以实现语义,但站在语言使用的角度上不用纠结这一点)
与引用的异同点(文心一言生成):
课本回答:
空指针可以用nullptr、NULL、0初始化(NULL为预处理变量,在编译前处理,但不推荐使用)
!非0指针作条件时均为true;指针比较时比较的是存储的地址而非所指对象
补充:指针用上面三个初始化时,if(p)均为false,其他情况为false
当*p
的值为零、false或者NULL时,条件为假。
要理解基本数据类型和类型修饰符的关系
const对象必须初始化;只能在const对象上执行不改变其内容的操作;
避免重复定义,const对象只在文件内有效;如果想共享,需要在声明和定义前都加extern
需要这么理解:实际上不存在常量引用,引用不允许改变绑定的对象,引用作为间接访问内存的形式,称之为常量引用是从引用的角度来看绑定的对象,将对象视为常量,即不能通过引用修改绑定的对象而不是不能修改引用绑定哪个对象(因为永远也不能修改)
!带有复杂修饰符的类型从右往左阅读比较清晰
初始化常量引用时有特殊情况:
int i=23;
const int &r1=i; //允许将const int& 绑定到一个普通的int对象
const int &r2=23; //允许将const int&绑定到字面值常量
const int &r3=r1*2; //允许将const int&绑定到表达式
int &r4=r1*2; //错误,r4是一个非常量引用
也就是说常量引用只限制了通过常量引用不可以修改绑定的对象,至于对象是不是常量则没有规定
常量指针可以类比常量引用:从指针的角度不可修改所指对象
指针常量指指针本身不可改变,即永远保存同一个地址(因为指针本身是个对象所以可以这样),实际上引用底层就是指针常量
const
是顶层 const
;const
是底层 const(一般说的是指针和引用,只有这两种类型用于间接访问内存)
只有指针可以同时有两层属性,其他类型要么顶层要么底层,见下图例子
底层const需要注意拷贝时应有相同的底层const或数据类型能转换(一般就是nonconst可以复制给底层const,反过来不行),见下例:
两个条件:值不变;编译期确定值
比如字面值(算术类型、引用、指针)、用常量表达式初始化的const对象等
constexpr用于指针时,把指针设置为顶层const
一种是使用typedef关键字:
一种是使用using别名声明:
auto会忽略顶层const,保留底层const;
auto引用保留顶层const
适用场景:用表达式的类型确定变量的类型,但是不使用表达式的值
和auto不同的是:decltype保留顶层const和引用
C++ decltype类型推导完全攻略
( )
包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,那么 decltype(exp) 的类型就和 exp 一致,这是最普遍最常见的情况。( )
包围,那么 decltype(exp) 的类型就是 exp 的引用;假设 exp 的类型为 T,那么 decltype(exp) 的类型就是 T&。decltype specifier - cppreference.com
上面提到了decltype的推导规则,尤其注意左值推导和括号那一条,总之推导结果和表达式形式相关
也是练习2.38的答案
总之三点:表达式计算与否;顶层const保留与否;decltype看括号和左右值
比如#include、#define等#开头的指令在预处理阶段进行执行
这里的#ifndef一系列可以保证类定义的唯一性
第二章结束