- 初始化与赋值
初始化的含义是创建变量的时候赋予其一个初始值,赋值的含义是把对象的当前值擦除,而以一个新值来替代。
列表初始化:int units = 0; int units = {0}; int units{0}; int units(0);
但是如果初始值存在丢失信息的风险,编译器将报错。
定义在函数体内部的内置类型变量将不被初始化。未被初始化的内置类型变量的值是未定义的,如果拷贝或者访问该值将引发错误。类的对象如果没有显式地初始化,则其值由类确定。 - 分离式编译
将声明和定义区分开来,声明使得名字为程序所知,文件如果想使用别处定义的名字则必须包含对那个名字的声明。定义负责创建与名字关联的实体,申请存储空间,也可能会为变量赋一个初始值。
extern 声明一个变量而不是定义它。
任何包含了显式初始化的声明即成为定义。
变量能且只能被定义一次,但是可以被多次声明。
定义在函数体外的标识符不能以下划线开头。 - 作用域
std::cout << ::reused
显示的访问全局变量,因为全局作用域没有名字,所以当作用域操作符左侧为空,向全局作用域发出请求。 - 复合类型
- 引用
引用为对象起了另外一个名字,引用类型引用另外一种类型,通过声明符写成&d的形式来定义引用类型。int &refVal = ival; //refVal指向ival
定义引用的时候,程序把引用和它的初始值绑定在一起,一旦初始化完成,引用将和它的初始值对象一直绑定在一起,所以引用必须初始化。
引用本身不是一个对象,所以不能定义引用的引用。引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定。 - 指针
指针也实现了对其它对象的间接访问,指针本身就是一个对象,允许对指针赋值和拷贝。int *d;//定义指针
。
指针存放某个对象的地址,获取该地址,使用取地址符,int *p = &ival;
,引用不是对象,没有实际地址,所以不能定义指向引用的指针。
其它所有指针类型都要与它所指向的对象严格匹配。
如果指针指向了一个对象,允许使用解引用符*来访问对象。int val = 42; int *p = &val; cout << *p;
,如果给解引用的结果赋值,实际上就是给指针所指的对象赋值。
空指针int *p1 = nullptr;
得到空指针最直接的方法是用nullptr来初始化指针。或者将指针初始化为0,但是不能赋给int变量的0,int *p2 = 0;
或者是实用cstdlib中的预处理变量NULL赋值,#include cstdlib int *p3 = NULL;
预处理器是运行与编译过程之前的一段程序,预处理变量不属于命名空间std,由预处理器负责管理,所以不需要加上std::,最好使用nullptr
指针最好初始化,定义了对象之后再定义指向它的指针。或者先初始化为nullptr
赋值永远改变的是等号左侧的对象,pi改变是指针,*pi改变的是指针指向的对象。
void*指针,可以用于存放任意对象的地址,double obj = 3.14; void *pv = &obj;
,但是不能直接操作void*指针所指的对象,因为并不知道对象是什么类型,因此无法再这个对象上操作。
void*来看内存空间就是内存空间,没办法访问内存空间中存储的对象。
类型修饰符如*,&只是声明符的一部分,变量的定义包括基本数据类型和一组声明符。 所以要定义多个指针变量必须这样int \*p1, \*p2;
指针的指针,指针式内存中的对象,因此也有自己的地址,允许把指针的地址再存放到另一个指针之中。
**表示指向指针的指针,int ival = 1024; int *pi = &ival; int \*\*ppi = π
所以如果要访问最原始的那个对象,需要对指针的指针做两次解引用,**ppi。
指针的引用,int i = 43; int *p; int *&r = p;//r是对指针p的引用。 r = &i; *r = 0;
从右往左阅读r的定义,离变量名最近的符号对变量的影响有最直接的影响,因此r是一个引用。*说明r引用的是一个指针。从右向左阅读弄清楚真实含义
- const
const对象一旦创建后值就不能再改变,所以const对象必须初始化,const int i = 43;
默认情况下,const对象被设定为仅在文件内有效,当多个文件中出现了同名的const变量时候,其实等同于在不同文件中分别定义了独立的变量。
也可以在一个文件中定义const,在其它多个文件中声明并且使用它。const不管是声明还是定义都添加extern关键字,这样就只用定义一次。
extern const int bufSize = fcn();
用extern加以限定使其被其它文件使用。
extern const int bufSize;
extern限定,作用是指明bufSize并非本文件所独有,它的定义将在别处出现。
- const的引用
const int ci = 1024; const int &r1 = ci;
引用及其对应的对象都是常量,引用和被绑定的对象关系是不变的。
引用的类型必须与所引用的类型一致,但是初始化常量引用允许使用任意表达式作为初始值,只要该表达式结果能转换成引用的类型。
const int &r2 = 43;
,double dval = 3.14; const int &ri = dval;
确保ri绑定一个整数,编译器进行了如下操作,const int temp = dval; const int &ri = temp;
ri绑定了一个临时量对象。但是如果ri不是常量的话,那么此时绑定的对象是临时量而不是dval,所以这样不能改变dval值,因此这样行为是非法的。
对const的引用可能引用一个并非const的对象int i = 43; const int &r2 = i;
指向常量的指针不能用于改变其所指对象的值,存放常量对象的地址,只能使用指向常量的指针。
const double pi = 3.14; const double *cptr = π
指针的类型必须和所指向对象的类型一致,但是允许令一个指向常量的指针指向一个非常量对象,double dval = 3.14; cptr = &dval;
指向常量的指针仅仅要求不能通过该指针改变对象的值。
const指针,常量指针说明指针存的值不能再改变了,不变的是指针本身的值而非指向的那个值。int errNumb = 0; int *const curErr = &errNumb; const double pi = 3.14; const double *const pip = π//指向常量对象的常量指针
,从右往左读,curErr是一个常量对象,*表示是常量指针,pip是一个常量指针,指向常量对象。
- 顶层const
顶层const表示指针本身是一个常量,底层const表示指针所指的对象是一个常量。用于声明引用的const都是底层constconst int &r = ci;
当执行对象的拷贝操作时候,拷入和拷处的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。 - 常量表达式
值不会改变并且在编译过程就能得到计算结果的表达式,const int max = 20; const int limit = max + 1;
constexpr变量,声明为这种类型表示是一个常量,constexpr int mf = 20;
算术类型,引用和指针都属于字面值类型,指的是编译时候就能得到结果的类型。所以可以定义成constexpr类型。
constexpr把它定义的对象置为了顶层const,constexpr int *q = nullptr;
q是常量指针。constexpr const int *p = &i;
p是常量指针,指向整形常量i
- 类型别名
typedef double wages; typedef wages base, *p;
wages是double的同义词,base也是,p是double *的同义词。
别名声明,using SI = Sales_item;
typedef char *pstring; const pstring cstr = 0; const pstring *ps;
指向char的常量指针
auto定义的变量必须有初始值,声明多个变量的时候该语句的所有变量的初始基本数据类型必须一样。
如果推断出的auto类型是一个顶层const,那么const auto f = ci;
- decltype类型指示符
decltype作用是选择并且返回操作数的数据类型,decltype(f()) sum = x;
sum的类型就是函数f的返回类型
如果表达式内容是解引用操作,则decltype将得到引用类型,int i = 42, *p = &i; decltype(*p) c//必须初始化;
c的类型就是int &
变量名如果加上括号,编译器会把它当成表达式,所以decltype就会得到引用类型,decltype((i)) d;//d是int &必须初始化
- 头文件
为了确保各个文件中类的定义一致,类通常被定义在头文件中,类所在头文件的名字应与类的名字一样。Sales_data类定义在名为Sales_data.h的头文件中。
头文件包括那些只能被定义一次的实体,类,const,constexpr变量。
确保头文件多次包含能安全工作的是预处理器,是在编译前执行的程序。
头文件保护符,预处理变量有两种状态,已定义和未定义,#define将名字设定为预处理变量,#ifdef当且仅当变量已经定义时为真,#ifndef当且仅当变量未定义时候未真。直到用到#endif为止。
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data{
};
#endif```