C++的对象类型决定了能对该对象进行的操作。一条表达式是否合法依赖于其中参与运算的对象的类型。Python在程序运行时检查数据类型。C++是一种静态数据类型,他的类型检查发生在编译时。
2.1基本内置类型
算术类型分为两类:整形和浮点型
一个char的大小和一个机器字节一样。
其它字符类型用于扩展字符集:wchar_t类型用于确保可以存放机器最大扩展字符集中的任意一个字符,类型char16_t和char32_t则为Unicode字符集服务。
除了字符和布尔类型之外,其他类型用于表示不同尺寸的整形。c++语言规定一个int至少和一个short一样大,一个long至少和一个int一样大,一个longlong至少和一个long一样大,数据类型longlong是在c++11中新定义的。
可寻址的最小内存块称为“字节(byte)”,存储的基本单元称为“字(word)”.他通常由几个字节组成。
浮点型可表示单精度、双精度和扩展精度值。C++标准制定了一个浮点数有效位数的最小值。通常float以1个字(32比特)来表示,double以2个字(64比特)来表示,long double以3或4个字来表示。一般来说,类型float和double分别7和16个有效位。类型long double则常用于有特殊浮点需求的硬件。具体实现不同,精度也不相同。
类型 int、short 、long和long long都是带符号的 ,通过添加unsigned 变成无符号的,类型unsigned int可以缩写为unsigned。
其中字符型被分为了三种:char、signed char和unsigned char。
类型char和类型char 和类型signed char不同。但是字符的表现只有后两种,类型char会由编译器不同变成其中一种。
使用char明确指出是那个类型。 双精度浮点数和单精度浮点数的计算代价相差无几。事实上,对于某些机器,双精度运算甚至比单精度还快。
int r=3.98;
cout<<r<<endl;
// 输出为3
当赋给带符号类型一个超出他范围的值,结果是未定义的,此时程序可能继续工作,可能崩溃,可能生成垃圾数据。 避免这种情况,如何吧int看成固定长度的,这样的程序就是不可移植的。
不要无符号和有符号在一个表达式。
字面值常量:值一看就知道,每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了他的数据类型,以0开头为8进制,以0x开头为16进制。字面值有个类型,十进制字面值的类型是、int、long、longlong中最小的那个能容纳下。八进制和十六进制是int、unsigned int、long......unsigend longlong。如果最大的都放不下就产生错误。
尽管整型字面值可以存放在带符号类型,但是严格来说,字面值符号之神对字面值取负号,并不在字面值之内。、默认的浮点字面值是double
字符串字面值的类型实际上是由常量字符构成的数组。编译器为每个字符串的结尾添加一个空字符。
有两类字符程序员不能直接使用,一类是不可打印的字符,如退格或其它控制字符因为没有可视图符。另一类是在c++中有特殊含义的字符,需要用到转义序列,如换行符 \n
泛化的转义序列:\x后紧跟1个或多个十六进制数字,或者\后有1、2、3个八进制数
2.2 变量
对象是指一块能存储数据并具有某种类型的内存空间。
初始化和赋值不同,初始化时创建变量时赋予值,赋值时把当前值擦除,用新的值来替代。
列表初始化会拒绝丢失信息的初始化。
定义于函数体内的内置类型没有初始化,值未定义。类对象没有初始化,由类确定。
声明为了让名字为程序所知,为了支持多个文件编译,定义负责创建与名字关联的实体。
C++是一种静态类型,在编译阶段检查类型。
2.3 指针
引用只是别名,不能和字面值和表达式的结果绑定。引用不是对象。
指针时对象允许对指针赋值和拷贝。
定义指针:
int *p;
int r=10;
p=&r;
&和*跟在类型后面是引用和指针,不然代表取地址和解引用。
指针的类型和赋值的类型必须匹配。
空指针是不指向任何对象,用字面值nullptr初始化指针。(c++11)
NULL空指针在头文件cstdlib中,值是0
void*是一种特殊的指针类型,可用于存放任意对象的地址。
*和&都是声明符的一部分
面对一条复杂的指针或引用,从右往左阅读。
2.4 const限定符
const对象必须初始化。可以是任意复杂的表达式。
默认情况下,const仅在文件内有效。
通过添加extern关键字,在其它多个文件中声明并使用
引用类型必须与其所引用对象的类型一致,但是有两个例外,第一是在初始化常量引用时可以用任意表达式作为初始值,第二是允许一个常量引用绑定非常量对象、字面值、一般表达式
double dval=3.1
const int &r=dval;
等价于
const int temp=dval;
const int &r=temp;
//如果不是const那么r引用一个临时量没有意义。
指向常量的指针(不能改变值,能换指向)
同样指向常量的指针也没有规定所指向的对象必须是一个常量
常量指针(不能换指向,能改变值)
//指向常量的指针
const double pi=3.1;
const int *r=π
//常量指针
int err=10;
int *const cur=&err;
只能改变小的去指向改变大的,反之不行,(const能指向变量,变量不能指向const)
用名词顶层表示指针本身是一个常量,用名词底层表示指针所指的对象是一个常量
const int *const p3=p2;
靠右的是顶层,靠左的是底层
只有底层const的p2可以拷贝由顶层和底层的p3,因为不会改变他,但是p不能拷贝p3,因为会改变他。
常量表达式是指不会改变并且在编译过程就能得到计算结果的表达式。
constexpr变量,以便由编译器来验证 变量的值是否是一个常量表达式,声明为constexpr的变量类型一定是一个常量。
constexpr int sz=size();
//当size是一个constexpr函数时,才是正确的语句
算术类型,引用和指针都属于字面值类型,自定义类 string。。。不属于字面值类型,也不能定义为constexpr。
尽管指针和引用都能定义成constexpr,但他们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者0,或者存储在某个固定地址中的对象。
函数体内定义的变量一般来说并非存放在固定的地址中。
const int *p=nullptr;
constexpr int *q=nullptr;
相反,一个是指向整型常量的指针,一个是指向整数的常量指针
2.5 处理类型
类型别名,
typedef double wages;
typedef wages base,*p; //base 是double的同义词,p是double*的同义词
using SI =Sales_item;
typedef char *pstring;
const pstring cstr=0; //cstr是一个指向char的常量指针
等价于
char * const ctsr=0;
const pstring *ps; //ps是一个指针,他的对象是指向char的常量指针
auto让编译器通过初始值来推算变量的类型。auto定义的变量必须有初始值。
auto在一条语句中声明多个变量,但是一条语句只能有一个基本类型。
auto sz=0,pi=3.14; //错误,有两个类型
编译器会对初始值有适当的改变。
比如让·一个引用对象auto那么auto会去掉引用。
其次auto会忽略掉顶层const,同时底层const则会保留
int i=0,&r=i;
auto a=r; //a是一个整形
const int ci=i, &cr=ci;
auto b=ci; \\b是整形
auto c=cr; \\ c是整形
auto d=&i; \\ d是整形指针
auto e=&ci; \\ e是一个指向整形常量的指针
如果是推断出auto类型是一个顶层const,需要明确指出:
const auto f=ci;
可以将引用类型设为auto
const auto &f=ci;
const auto &h=42;
auto &h=42; \\错误 42字面值,auto默认没有const 不能引用字面值
auto &m=ci,*p=&ci; //正确,m是对整形常量的引用,p是指向整形常量的指针
auto &n=i,*p2=&ci; //错误;i的类型是int,&ci的类型是const int
符号&和*只从属于某个声明符,而非基本数据类型的一部分。
希望从表达式的类型,推断出要定义的变量的类型,但是不想用该表达式的值初始化变量,
decltype,他的作用式选择并返回操作数的数据类型。
decltype(f()) sum=x;
不调用函数f。当调用发生时,f的返回值类型作为sum的类型。
const int ci=0,&cj=ci;
decltype(ci) x=0; //x是const int
decltype(cj) y=x; //y是const int&
decltype(cj) z; //错误,z是const int&,必须初始化
一个引用类型通过,decltype结果是引用类型,假如变成表达式的一部分,比如decltype(r+0)那么就是具体值,就是int类型
指针解引用是引用类型。
int *p=&i;
decltype(*p) sum; //错误,解引用后默认加个引用,所以这个类型是int &
decltype((i)) 是引用类型
decltype(i) 是int类型
头文件一旦改变,相关的源文件必须重新编译以获取更新过的声明。
C++程序会用到一项预处理功能头文件保护符,头文件保护符依赖于预处理变量。预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理变量,另外两个指令分别检查某个指定的预处理变量是否已经定义:#ifdef 当且仅当变量已经定义时为真,#ifndef当且仅当变量未定义是为真,一旦检查结果为真,则执行后续操作直至遇到#endif
类定义可以使用class或struct
二者默认的继承、访问权限不同
struct时public 、class是private的