开始
闲杂
- 头文件的引用,使用#include引用标准库的头文件名,#include"my_head.h" 使用非标准库的头文件。
- 类的成员函数:使用点运算访问一个成员函数时,我们往往是想调用该成员函数,这需要调用运算符()。这一对圆括号就是调用运算符,里面放置实参(argument)列表(可能为空。
变量与基本类型
内置类型:
- 算术类型。又分为整型(包括字符和布尔类型)和浮点类型。浮点类型中,float以32个bit(一个字)来表示,double以2个字表示。
- 空类型(void)。
变量
变量提供了一个具名的可供程序操作的存储空间。
对象?object是一块能存储数据并具有某种类型的存储空间。
初始值
当对象在创建时获得了一个特定的值,我们说这个对象被初始化了。
double proce = 1.99 ;
实际上,初始化时一个比较复杂的问题,其和赋值并不是同一个操作。
初始化并不是赋值,初始化的含义时创建变量时赋予其一个初始值,而赋值是将当当前的值擦除,以一个新值来代替。
默认初始化:对于内置类型的变量未被显示初始化,它的值由定义的位置所决定。定义于任何函数体之外的变量被默认初始化为0。而例外情况是,一个违背初始化的内置类型变量的值是未定义的。见下面这个程序
int global_int ; //默认初始化为0
int main(){
int local_int ; // 未被初始化
string local_str ; //未被初始化
}
区分变量的声明与定义
c++语言支持分离式编译(separate compilation)机制,这允许程序被分割为若干个文件,每个文件可被独立编译。为了支持分布式编译,c++语言中的声明和编译区分开来。
声明使得名字为程序所知,一个文件如果想使用别处定义的名字必须包含对那个名字的声明。而定义负责创建与变量名所关联的实体。
二者差别在于:声明规定变量的类型和名字。定义除此之外,会申请存储空间(还可能进行初始化)。
要想声明一个变量,要在变量名之前添加关键字extern,并且
extern int i; //声明i而非定义i
int j ; //声明并定义j
任何包含了显示初始化的声明即成为定义。
变量只能被定义依次,但是可以被多次声明
声明还是挺重要的。
名字的作用域
scope(作用域),大多数作用域都以花括号进行分隔。
- 全局作用域:定义在函数体之外
- 块作用域:函数内定义,只能局部访问
int i = 100 ;
int sum = 0 ;
for (int i = 0; i< 10 ; i++){
sum += i ;
}
cout << i << sum << endl; //将输出i=100和sum = 45
引用与指针
引用(reference) 是为对象起了另外一个名字。
int i = 100 ;
int &refer_i = i ; //引用标识符&
itn refer_null ; //会报错,引用必须要初始化
cout << refer_i << endl;
指针
要理解一些符号的多重涵义,看例子:
int i = 34 ;
int &r = i; //声明
int *p; //定义指针
float *q ;
p = &i; //&取变量i的地址,赋值给p
q = &i; //会报错,指针类型要与数据类型匹配
*p = i ; //*出现在表达式中,是一个解引用符
int &r2 = *p ; //&是声明的一部分,*是一个解引用符
建议:初始化所有指针,使用未经初始化的指针是引发运行错误的一大原因。若不知道将其指向何处,可以将其初始化为nullptr或者0
指针操作:
我们时常看到这样的判断:
int ival = 1 ;
int *pi = &ival ;
if(pi)...
规则是:任何非0指针对应的条件值都是true。
特殊情况:void指针。void指针是一类特俗的指针类型,可存放任意对象的地址。
doule obj = 3.14 ;
void *pv = &obj ;
void指针的局限性在于:不能直接操作void * 所指向的对象,因为我们无法知道找个对象是什么类型,也就无法确定在其商面能有什么操作。
复合类型:
注意这句话:
int* p ; //这样是合法的,但是可能产生误导
int* p1,p2; //实际上,p1是一个指针,p2是一个int
指向指针的指针
int ival = 1024 ;
int *pi = &i ; //指向一个int型的数
int **ppi = &pi ; //指向一个int类型的指针
cout << **ppi << endl ; //会输入ival的值
const限定符
const是比较重要的,在《effictive c++》的就提到,我们应当多使用const变量而非 #define。
const是这样一种变量,它的值不能被改变。对于每个const对象,在编译的过程中会变该变量换成对应的值。
在头文件中,可以通过对const变量使用extern关键字生气成为声明,而使得其他文件能够使用它。不过,定义只能在一个文件中。
const的引用:
可以把引用绑定道const对象上,就像绑定道其他对象上一样,称为对常量的引用。
const int ci= 1024 ;
const int &r1 = ci;
r1 = 42 ; //错误,r1是对常量的引用
int &r2 = r1; // 错误,试图让一个非常量引用指向一个常量对象
const int &r3 = r1 * 2 ; //正确,常量引用常量
int &r4 = r4*2; //错误,r4是一个非常量的引用
double dval = 3.14 ;
const int &ri = temp ; //这个ri引用了一个int型的数,单dval使double类型的,因此,在编译器中,实际上进行了:
const int temp = dval; //由double生成一个临时的整型常量
const int &ri = temp;
指针和const
const指针是一个指向常量的指针。一个const常量,只能使用const ptr。
const double pi = 3.14;
double *ptr = &p; //报错,ptr是一个普通指针
const double *cptr = &p; //可以,但是不能通过cptr改变dval的值
顶层const
顶层const表示指针本身是一个常量,而用底层const表示指针所指的对象是一个常量。
指针的值的四种状态:
- 指向一个对象
- 指向近邻对象所占空间的下一个位置
- 空指针
- 无效指针,上述三种情况之前的值
int i = 0;
int *const p1 = &i ; // 顶层const,p1的值无法改变
const int c1 = 2;
const int *p2 = &ci ; //可以改变p2的值,这是一个底层const指针
const int *const p1 = p2; //左边的const是底层const,代表这个指针,靠左的是底层const,表示指向一个cosnt常量
constexpr和常量表达式
常量表达式,是值不会改变并且在编译的过曾中就可以得到计算结果的表达式。
const int max_file = 200; //max_file是常量表达式
const limit = max_file + 1 ; //limit是常量表达式
const int sz = get_size(); //sz并不是常量表达式
auto
auto类型说明符,它能让编译器替我们去分析表达式所属于的类型,其是通过初始值来推算变量的类型,因此,auto定义的变量必须有初始值。
参考文献
《C++ primer 中文版》