Thinking in C++重点知识有哪些(C++,编程语言)

时间:2024-05-06 07:37:21 作者 : 石家庄SEO 分类 : 编程语言
  • TAG :

    Thinking+in+C%2B%2B%E9%87%8D%E7%82%B9%E7%9F%A5%E8%AF%86%E6%9C%89%E5%93%AA%E4%BA%9B

解释器(interpreter)

编译器(complier)

预处理器(preprocessor)处理预处理指令

编译分为两遍,第一遍解析预处理代码生成节点数,在进行第二步之前进行全局优化(global optimizer),第二遍代码生成器(code generator)解析代码树生成机器语言或者汇编语言

静态类型检查在第一遍中进行

编译过程的最后阶段,把编译器生成的目标模块连接成可执行文件(操作系统可以识别)

return语句退出函数,返回到函数调用后的那点,联想栈的操作

由库管理器来管理对象模块,这个库管理器就是管理.lib/.a文件的

for循环首先执行initialization,其次判断conditional,满足则进入循环,执行完循环进行step步骤

switch中的selector必须为整数值,integral-value必须为整形数值

selector也可以为enum类型值

用于改变基本内建类型的含义并将基本类型扩展成一个更大的集合
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*指针可以赋值为任何类型的地址,但是会丢失类型信息,不恰当的类型转换会导致程序崩溃

从定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号,也就是说作用域由变量所在的最近一对括号确定。

全局变量的生命周期一直到程序结束,可以使用extern关键字来使用另一个文件中的全局变量

static变量优点是在函数范围之外它是不可用的,不可以轻易改变,使错误局部化,当应用static于函数名和所有函数外部变量时,它的意思是“在文件的外部不可以使用该名字”,即拥有文件作用域如

内部连接:只对正在编译的文件穿件存储空间,为每一个标识符创建单独的存储空间,内部连接由关键字static指定

外部连接:对所有编译过的文件创建一个单独的存储空间,即将所有变量和函数包含在该空间中

typedef existing-type-description alias-name

typedef unsinged long ulong;

typedef int* intPtr

typedef struct MyStruct{
//这里是C常营的结构定义
} MyStruct;

typedef int (*fun)(int,int) //函数指针别名为fun

c++中对enum的检查更为严格,c中允许a++(a为color型枚举),但是c++中不允许,因为a++做了两次转换,首先将color类型转换为int,然后自增1之后,将该值在转换成color,第二次转换时非法的

使用friend关键字可以访问内部私有成员变量或者成员函数

Y::f(X*)引用了一个X对象的地址,编译器知道如何传递一个地址,不管被传递的是什么对象,地址具有固定大小,当试图传递整个对象时,编译器必须知道X的全部定义以确定它的大小以及如何传递,使用不完全类型说明(incomplete type specification),即在struct Y之前声明struct X;

嵌套结构不能自动获得访问private成员权限,可以使用如下方法访问

声明嵌套结构

声明该结构是全局范围内使用的一个friend

定义该结构

Handler.h文件中struct Cheshire是一个不完全的类型说明或者类声明,具体类定义放在了实现文件中

当void*指向一个非内建类型的对象时,只会释放内存,不会执行析构函数

Object没有默认构造函数,数组声明初始化时将报错,object[1]必须有默认构造函数进行初始化,否则报错当且仅当没有构造函数时编译器会自动创建一个默认构造函数

使用范围和参数可以进行重载

编译成功,在C中连接成功,但是在C++中连接出错,这是C++中的一种机制:类型安全连接

enum没有类型名,因为后面没有必要涉及美剧的类型名称,所以枚举类型名可选,非必须

union没有类型名和标识符,称为匿名联合(anonymous union),不需要使用标识符和以点操作符方式访问这个union的元素

访问一个匿名联合成员就像访问普通变量一样,唯一区别在于:该联合的两个变量占用同一内存空间,如果匿名union在文件作用域内(在所有函数和类之外),则它必须声明为static,以使它有内部的连接

只有参数列表的后部参数才可以是默认的

一旦在一个函数调用中开始使用默认参数,那么这个参数后面的所有参数都必须为默认的

其中version 2除了i,flt之外中间参数就是占位符参数

C++中const默认为内部连接,仅在const被定义的文件中才可见,在连接时不能被其它编译单元看见,当定义一个const时必须赋值给它,除非使用extern进行说明

extern const int bufsize;

通常c++不为const创建空间,将其定义保存在符号表内,但是上面的extern进行了强制内存空间分配,另外如取const的地址也是需要存储空间的分配。

对于复杂的结构,编译器建立存储,阻止常量折叠。在C中const默认为外部连接,C++默认为内部连接.出现在所有函数外部的const作用域是整个文件,默认为内部连接

const修饰指针正指向的对象 const int* a;

const修饰在指针中的地址 int* const a;

const对象地址不可以赋值给一个非const指针,但是可以吧一个非const对象地址赋值给一个const指针

字符数据的字面值:

指针cp指向一个常量值,即常量字符数组,数组cp的写法允许对howdy进行修改

在求表达式值期间,编译器必须创建零时变量,编译器为所有的临时变量自动生成为const

const指针不可以赋值给非const指针,但是非const指针可以赋值给const指针

函数v()返回一个从字符数组的字面值中建立的const char *,在编译器建立了它并把它存储在静态存储区之后,该声明实际上产生该字符数组的字面值的地址

函数w()返回值要求这个指针以及这个指针所指向的对象均为常量,与函数v()类似,因为i是静态的,所以函数返回后返回值仍然有效

const int* const w()只有在作左值时第二个const才能显现作用,所以w()返回值可以赋值给const int *

可以将临时对象传递给const引用,但不能将一个临时对象传递给接收指针的函数,对于指针必须明确接受地址(临时变量总是const)

必须在构造函数的初始化列表中进行初始化

一个内建类型的static const可以看成编译期间的常量,但是该static const必须在定义的地方进行初始化

无标记enum也可以看成为编译期间常量,一个枚举在编译期间必须有值

若将一个成员函数声明为const,则该成员函数可以被const对象调用

const成员函数可以调用非const成员和const成员,非const成员函数同样可以使用const成员

const对象只能调用const成员函数,非const对象调用非const成员函数

内联函数与普通函数一样执行,但是内联函数在适当的地方像宏一样展开,不需要函数调用的开销(压栈,出栈),任何在类内部定义的函数自动成为内联函数

内联函数体过大时,编译器将放弃使用内联

当取函数地址时,编译器也将放弃内联

一个内联函数在类中向前引用一个还没有声明的函数时,是可以的,因为C++规定只有在类声明结束后,其中的内联函数才会被计算

类中包含子对象,构造函数先调用子对象的构造函数,如果没有默认构造函数,则必须在初始化列表中进行初始化,然后在调用类的构造函数

类中包含子对象,先调用类的析构函数在调用子类的析构函数

在固定地址上进行存储分配,在一个特殊的静态数据区上创建,不是在堆栈上产生

对一个特定编译单位来说是局部的,static可以控制名字的可见性,该名字在这个单元或者类以外是不可见的

如果没有为一个内建类型的静态变量提供一个初始化值,编译器会确保在程序开始时它被初始化为零(转化成适当的类型)

如果在定义一个静态对象时没有指定构造参数时,该类必须有默认的构造函数

常量、内联函数默认情况下为内部链接

所有全局对象隐含为静态存储

对static函数意味着只在本单元可见,成为文件静态(file static)

static成员必须在类外初始化,如果不初始化,则编译器不会进行默认初始化,对于非内建类型,可以使用构造函数初始化代替“=”操作符

类内const成员必须在构造函数的初始化列表中进行初始化

static const变量(内建类型)必须在声明的地方就初始化

static对象数组,包括const和非const数组必须在类外部初始化

自定义class类声明为stctic,不管其为const或者非const都必须在类外初始化

类的静态成员必须进行初始化后才可以使用

类的静态成员函数不能访问一般数据成员或者函数,只能访问静态数据成员,也能调用其他静态成员函数

静态成员函数没有this指针

优先级低的先读
*p[] 指针数组
(*p)[] 数组指针,即指向一个数组

函数的地址:函数名后不跟参数

指向整个数组的指针,即是一个指针,而不是一个数组,优先级低的先读
*p[] 指针数组
(*p)[] 数组指针,即指向一个数组

pd指向数组,*pd就是数组,而(*pd)[i]是数组中的元素,即函数指针
函数调用:

namespace只能在全局范围内定义,但是可以相互嵌套

在namespace定义的结尾,右花括号后面不必跟一个分号

可以按类的语法来定义一个namespace,定义的内容可以在多个头文件中延续,就好像重复定义这个namespace

一个namespace的名字可以用另一个名字来作为它的别名
namespace lib = MyLib;

不能像类一样创建一个名字空间的实例

将局部名字放在一个未命名的名字空间中,不需要加上static就可以作为内部连接

new计算内存大小,并调用构造函数,malloc需要手工计算内存大小,不调用构造函数

delete先执行析构函数,在清空内存,free直接清空内存
delete用于void*时将不会调用析构函数,直接清空内存

重载的new必须有一个size_t参数,该参数由编译器产生并传递给我们,分配内存的长度,必须返回一个指向等于该长度的对象的指针,如果没有找到存储单元,则返回一个0,然而如果找不到存储单元,不能仅仅返回0,还应该有new-handler或产生一个异常信息

new返回void*,而不是指向任何特定类型的指针,只需要完成内存分配,而不是完成对象的创建,直到构造函数调用才能完成对象的创建,调用构造函数是编译器完成的

delete参数是由new分配的void*指针,该参数是在调用析构函数后得到的指针,析构函数从存储单元中移去对象

这里使用printf(),puts()等函数,而不是iostreams,因为使用iostreams对象时(全局对象cin,cout,cerr),调用new分配内存,printf不会进入死锁状态,它不调用new来初始化自身

//p328

主要思想:使用static数组以及一个bool数组,返回static数组的下标地址,进行new,得到static下标数组进行delete
void* operator new(size_t) throw(bad_alloc);
void operator delete(void*);

//p331

//p333

主要思想:使用new运算符重载,但是不对delete运算符重载,指定内存位置new
void* operator new(size_t,void*);

成员对象如果没有默认的构造函数,必须显示的进行初始化,即在构造函数初始化列表中进行初始化

只有执行成员类型初始化之后,才会进入构造函数

没有对所有成员以及基类对象的构造函数调用之前,若基类没有默认构造函数则必须初始化,即在初始化列表中进行初始化,否则无法进入构造函数体

构造函数调用的顺序:首先调用基类构造函数,然后调用成员对象的构造函数,调用成员对象构造函数的顺序是按照成员对象在类中声明的顺序执行,最后调用自己的构造函数

析构函数调用次序与构造函数调用次序相反,先调用自己的析构函数,在调用成员函数的析构函数,最后调用基类析构函数

对于多重继承,构造函数调用顺序为继承时的声明顺序

构造函数

析构函数

operator=

静态成员函数与非静态成员函数的共同特点:
1. 均可以被继承到派生类中
2. 重新定义一个静态成员,所有基类中的其他重载函数会被隐藏
3. 如果我们改变了基类中的函数的特征,所有使用该函数名字的基类版本将会被隐藏。
4. 静态成员函数不可以是虚函数

使用私有继承是为了不允许该对象的处理像一个基类对象,一般private更适合于组合

私有继承成员公有化

基类拷贝构造函数的调用将一个Derived引用向上类型转换成一个Base引用,并且使用它来执行拷贝构造函数,向上类型转换是安全的

首先进行自我检查(是否对自身赋值),即this == &val,在进行运算,“=”运算符只允许作为成员函数进行重载

对于任何函数参数,如果仅需要从参数中读而不改变它,默认地应当做const引用传递。普通算数运算符(像“+”,“-”)和bool运算符不会改变参数,所以const引用为主要传递方式,当函数时成员函数时,就转换为const成员函数。只有会改变左侧参数的运算符赋值(如+=)和operator=,左侧参数不是常量,但因参数将被改变,所以参数仍然按地址传递

返回值类型取决于运算符的具体含义,如果使用该运算符产生一个新值,就需要产生一个作为返回对象的新对象。例如operator+必须生成一个操作数之和的对象,该对象作为一个常量通过返回值返回,所以作为一个左值不会被改变

所有赋值运算符均改变左值,为了使赋值结果能用于链式表达式(如a=b=c),应该能够返回一个刚刚改变了的左值的引用。但该引用并非一定要是常量引用,如(a=b).f(),这里b赋值给a,a调用成员函数f,因此所有赋值运算符的返回值对于左值应该是非常量引用(如果是常量引用,则f成员函数必须为const函数,否则无法调用该函数,这与愿望相违背)

对于逻辑运算符,人们至少希望得到一个int返回值,或者最好是bool值

成员函数

友元函数

作为常量通常通过传值方式返回。考虑二元运算符+,假设在表达式f(a+b)中使用,a+b的结果变为一个临时对象(Object),该对象被f()调用,因为它为临时的,所以自动被定义为常量,所以无论是否返回值为常量都没有关系。但是如果使用(a+b).f(),这里设返回值为常量规定了对于返回值只有常量成员函数才可以调用

返回值优化通过传值方式返回要创建的的新对象时,注意使用的形式,如operator+

该运算符必须是成员函数,而且只接受一个参数,可以返回一个引用,可以用于等号左侧。

该运算符一定是一个成员函数,它必须返回一个对象(或者引用),该对象也有一个指针间接引用运算符;或者必须返回一个指针,被用于选择指针间接引用运算符箭头所指的内容

指针间接引用运算符自动的为用SmartPointer::operator->返回的Obj*调用成员函数

//p294

所有一元运算符建议为成员

=()[]->->*必须为成员

+= -= /= *= ^= &= |= %= >>= <<=建议为成员

所有其他二元运算符为非成员

//p301引用计数

构造函数转换:构造函数能把另外一个类型对象(或者引用)作为它的单个参数,该构造函数允许编译器执行自动类型转换

运算符转换:运算符重载,创建一个成员函数,该函数通过关键字operator后跟随想要转换的类型的方法,将当前类型转换为希望的类型,自动类型转换只发生在函数调用值中,而不在成员选择期间

二义性错误

扇出错误:提供不止一种类型的自动转换

本文:Thinking in C++重点知识有哪些的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:怎么在vue中根据进入的路由实现原路返回下一篇:

12 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18