本文主要是阅读Thinking in C++ 第一卷的一些笔记。主要是一些注意点
Thinking in C++ Chapter 2
Translator:
- 解释器(interpreter)
- 编译器(complier)
编译器编译程序步骤:
- 预处理器(preprocessor)处理预处理指令
- 编译分为两遍,第一遍解析预处理代码生成节点数,在进行第二步之前进行全局优化(global optimizer),第二遍代码生成器(code generator)解析代码树生成机器语言或者汇编语言
静态类型检查在第一遍中进行
函数或者变量的声明与定义
void function();//声明
void function(){
}//定义
extern int a;//声明
int a;//定义
连接
编译过程的最后阶段,把编译器生成的目标模块连接成可执行文件(操作系统可以识别)
Thinking in C++ Chapter 3
函数返回说明
return语句退出函数,返回到函数调用后的那点,联想栈的操作
通常函数库
由库管理器来管理对象模块,这个库管理器就是管理.lib/.a文件的
关于for循环的说明
for(initialization;conditional;step)
for循环首先执行initialization,其次判断conditional,满足则进入循环,执行完循环进行step步骤
switch说明
switch(selector){
case integral-value:statement;break;
...
defualt:statement;
}
switch中的selector必须为整数值,integral-value必须为整形数值
selector也可以为enum类型值
说明符(specifier)
用于改变基本内建类型的含义并将基本类型扩展成一个更大的集合
1. int: short int / int / long int(使用short和long时,int关键字可以省略)
2. float/double: 没有long float只有long double,即:float / double /long double
3. signed/unsigned:符号位(适用于整形和字符型)
void*指针说明
void*指针可以赋值为任何类型的地址,但是会丢失类型信息,不恰当的类型转换会导致程序崩溃
变量的有效作用域
从定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号,也就是说作用域由变量所在的最近一对括号确定。
全局变量
全局变量的生命周期一直到程序结束,可以使用extern关键字来使用另一个文件中的全局变量
静态(static)变量
static变量优点是在函数范围之外它是不可用的,不可以轻易改变,使错误局部化,当应用static于函数名和所有函数外部变量时,它的意思是“在文件的外部不可以使用该名字”,即拥有文件作用域如
//file1.cpp
static int fs;
int main(){
fs = 1;
}
//file2.cpp
extern int fs;//编译器不会找到file1.cpp文件中的fs,即文件作用域
void function(){
fs = 100;
}
extern static int i;
int main(){
cout << i << endl;
}
static int i = 0;
将出现error,即全局静态变量声明是有文件作用域的,编译器将会产生错误
连接(linkage种类)
- 内部连接:只对正在编译的文件穿件存储空间,为每一个标识符创建单独的存储空间,内部连接由关键字static指定
- 外部连接:对所有编译过的文件创建一个单独的存储空间,即将所有变量和函数包含在该空间中
自动(局部)变量只是临时存在于堆栈中,连接器不知道自动变量,所以这些变量没有连接
预处理宏
#define PRINT(STR,VAR) \
cout << STR << VAR << endl; \
cout << VAR << STR <<endl
即可以像调用函数一样调用PRINT,这里预处理宏分行使用'\',宏只是展开,并替换
#define PRINT(STR,VAR) \
cout << #STR << VAR << endl
这里'#'表示STR字符串化(stringizing),比如:
int i = 0;
PRINT(i,i); //这里输出应该是 i:0
typedef语法说明
typedef existing-type-description alias-name- typedef unsinged long ulong;
- typedef int* intPtr
- typedef struct MyStruct{
//这里是C常营的结构定义
} MyStruct; - typedef int (*fun)(int,int) //函数指针别名为fun
enum说明:
c++中对enum的检查更为严格,c中允许a++(a为color型枚举),但是c++中不允许,因为a++做了两次转换,首先将color类型转换为int,然后自增1之后,将该值在转换成color,第二次转换时非法的
Thinking in C++ Chapter 5
友元
使用friend关键字可以访问内部私有成员变量或者成员函数
struct X;
struct Y{
void f(X*);
};
struct X{
private:
int i;
public:
void initialize();
friend void g(X*,int); //Global friend
friend void Y::f(X*); //struct member friend
friend struct z; //Entire struct is a friend
friend void h();
}
Y::f(X*)引用了一个X对象的地址,编译器知道如何传递一个地址,不管被传递的是什么对象,地址具有固定大小,当试图传递整个对象时,编译器必须知道X的全部定义以确定它的大小以及如何传递,使用不完全类型说明(incomplete type specification),即在struct Y之前声明struct X;
嵌套友元
嵌套结构不能自动获得访问private成员权限,可以使用如下方法访问
- 声明嵌套结构
- 声明该结构是全局范围内使用的一个friend
- 定义该结构
const in sz = 20;
struct Holder{
private:
int a[sz];
public:
void initialize();
struct Pointer;
friend Pointer;
struct Pointer{
private:
Holder* h;
int* p;
public:
void initialize(Holder* h);
void next();
void previous();
void top();
void end();
int read();
void set(int i);
};
};
void Holder::initialize(){
memset(a,0,sz*sizeof(int));
}
void Holder::Pointer::initialize(Holder* rv){
h = rv;
p = rv->a;
}
...
int main(){
Hodler h;
Holder::Pointer hp;
int i;
h.initialize();
hp.initialize(&h);
...
}
struct其他
//: Hadler.h
class Handler{
struct Cheshire;
Cheshire* smile;
public:
...
};
//:~
//:Handler.cpp
struct Handler::Cheshire{
int i;
...
}
...
Handler.h文件中struct Cheshire是一个不完全的类型说明或者类声明,具体类定义放在了实现文件中
Thinking in C++ Chapter 6
构造函数相应说明
class Object
{
public:
Object(int number = 0);
private:
int m_number;
};
//:~
//: main
int main(int argc, char *argv[])
{
int i = 0;
switch(i){
case 0:
Object obj1{
1};
break;
case 1: //error: cannot jump from switch statement to this case label "case 1:"
Object obj2{
2}; //jump bypasses variable initialization "Object obj1{1};"
break;
}
return 0;
}
上述代码报错
switch回跳过构造函数的的序列点,甚至构造函数没有被调用时,这个对象也会在后面的 程序块中程序块中起作用,这里产生错误
是确保对象在产生的同时被初始化。goto也会产生这样的错误。
delete void*
当void*指向一个非内建类型的对象时,只会释