文章目录
基础
代码
#include <iostream>
int main(int argc, const char * argv[]) {
std::cout << "Hello, World!"<< std::endl;
return 0;
}
向流写入数据
iostream
包含两个基础类型:istream
和ostream
;
istream
包含的对象有:cin
;
ostream
包含的对象有:cout
(标准输出),cerr
(标准错误),clog
(返回程序运行时的信息);
<<
将要输出的值写到cout
中,最终输出写入数据的标准输出。
endl
关闭与设备关联的缓冲区,将内容刷新到设备中。
标准库的名字
std
为命名空间,其作用有:
- 避免不经意的名字定义冲突;
- 避免使用库中相同名字导致的冲突。
注释
单行注释//
,多行注释/*...*/
。
变量和基本类型
基本类型
类型之间
强行赋值:bool
与int
,char
与int
,int
与float
/double
。
在特定的情况下,类型转换会自动发生:
- if语句中的整型;
- 算术表达式中的隐式类型转换。
类型之内
给带符号类型一个超出它表示范围的值时,结果是未定义(void)的。
无符号数与int
同时存在时,会转化为无符号数。
无符号数做运算时,要保证输出的结果不是负数(异常)。
变量
std::string str
,库类型string
的定义,表示可变长字符序列的数据类型。
对象:指一块能储存数据并具有某种类型的内存空间,被命名的对象称为变量。
初始化不是赋值,初始化是创建变量时赋予了一个初始值,赋值的含义是把对象的当前值擦除,用一个新值来代替。
内置类型变量未被显式初始化,它的值由定义的位置决定:定义于函数体之外的变量被初始化为0;定义于函数体内部的内置类型变量将不被初始化。因此,建议初始化每一个内置类型的变量。
C++中将定义和声明区分。声明使得名字为程序所知,一个文件如果想要使用别处定义的名字则必须要包含对那个名字的声明。定义负责创建与名字相关联的实体。
比如:extern int i
是声明i而非定义i;int j
声明并定义j。
如果extern
包含初始化,那么它变成了定义,而非声明。在函数体内部,如果对extern
进行初始化,将引发错误。且extern
只能为全局变量声明。
变量能且只能被定义一次,但可以被多次声明。
作用域
大多数作用域用花括号分隔。
同一个名字在不同作用域中可能指向不同的实体。名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。
main函数定义于花括号之外,拥有全局作用域(从声明开始至程序结束)。
被包含的作用域被称为内层作用域,包含着别的作用域的作用域被称为外层作用域。
作用域中一旦声明了某个名字,嵌套着的所有作用域中都能访问该名字。同时允许在内层作用域中重新定义外层作用域已有的名字。
复合类型
引用(refer to)
为对象起了另一个名字。
int ival=1024;
int &refVal = ival; //refVal指向ival
int &refVal12; // 报错:引用必须初始化
引用会和初始化对象绑定在一起。因为无法令引用重新绑定一个对象,因此必须初始化。
引用本身不是一个对象,所以不能定义引用的引用。
引用的类型必须与对象的类型一致,但有两种例外。
refVal
是引用的标识符。
指针(point to)
相同点:实现了对对象的间接访问。
不同点:指针本身就是一个对象,允许对指针赋值与拷贝,且在生命期内可以先后指向几个不同的对象;指针无需在定义时赋值。
int *ip1;
int *ip2=&ival; //&取地址符号
指针的值应该属于下列四种状态之一:
- 指向一个对象;
- 指向紧邻对象所占空间的下一个位置;
- 空指针,意味着指针没有指向任何对象;
- 无效指针,上述情况之外。
访问对象:
*p = 0; //*解引用符,可以得到指针所指的对象。
p = &ival; //得到地址。
生成空指针的方法:
int *p = nullptr; //推荐
int *p = 0;
int *p = NULL;
其他指针操作:
if(p) //pi如果是空指针,则为False,反之为True
复合类型的声明
一条语句可以定义不同类型的变量:
int i=1024,*p=&i,&r=i;
关于变量修饰符与基本数据类型的关系:
int* p1,p2;
int *p1,*p2;
int* p1;
int* p2;
// 变量修饰符号不能共用,需要分开写。
指向指针的指针:int **p = &p1
;为了访问最原始的对象,需要进行两次解引用符号**p
。
指向指针的引用:引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用int *&r=p
。要理解r的类型到底是什么,可以从右往左阅读r的定义。
const限定符
const类型的对象上只能执行不改变其内容的操作。
const对象一旦创建后其值就不能再改变了,所以const对象必须初始化。
const对象的常量特征仅仅在执行改变操作时才会发挥作用,当用这一对象初始化别的变量时,不用在乎其是否是一个常量。
默认状态下const类型仅在文件内有效。 编译器在编译过程中把用到该变量的位置都换成对应的值,因此包含const对象的值都需要能访问它的初始值才行。于是在其他文件中出现该变量时,等同于在不同文件中分别定义了独立的变量。
如果想在其他文件中共享该对象,必须在定义前加extern。
引用和const
对常量的引用(reference to const):
const int ci = 1024;
const int &r1 = ci //correct
int &r1 = ci // wrong
引用类型与原类型不同之例外1:初始化常量引用时允许用任意表达式作为初始值,只要表达式能转化为引用的类型即可。特别地,允许为一个常量绑定一个非常量的对象。
int i = 42;
const int &r = i;
这一过程可以拆分为:
const int temp = i;
const int &r = temp;
temp被称为临时量对象,这里让r绑定到了临时量上去,但是改变i依旧会改变r,而改变r却是非法的。
指针和const
指向常量的指针(point to const):
const double pi = 3.14;
const double *cptr = &pi
指针的类型必须与所指对象的类型一致,但有两个例外,即与常量引用一样,第一种例外情况是,允许令一个指向常量的指针指向非常量对象。
double pi =3.14;
const double *cptr = π
指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变。
常量指针:
int errNumb = 0;
int *const curErr = &errNumb;
const double pi = 3.14;
const double *const pip = π
把*放在const之前说明指针是一个常量,即不变的是指针本身的值,而非指向的那个值。
分析这一定义方式可以通过从右到左法识别。
顶层const
顶层const表示指针本身是一个常量。底层const表示指针所指的对象是一个常量。
顶层指的是对象自身的性质,底层指的是对象作用的性质。
顶层const可以表示任意的对象是常量,对任何数据类型都适用;底层const则与指针、引用等复合类型的基本数据类型部分有关。
只有指针,既可以是一个顶层const,也可以是一个底层const,而引用只是底层const。
对顶层const而言,初始化阶段,拷入和拷出的对象是否是常量没有什么影响(除了指针类型与对象类型一致 const int);
对底层const而言,初始化阶段以及赋值阶段,拷入和拷出的对象都必须有相同的底层const的资格或者可以进行类型转换(指针类型与对象类型一致 const int)。
包含可包含底层const的对象,需要两者都有资格,不可包含底层const的对象则进行类型转换。
出错的情况如下:
int i = 42;
int const *a = &i;
int *b = &i;
b = a;
处理类型
类型别名
方法一:
typedef double wages;
方法二:
using wages = double;