c++const用法/4 v2, -0x2是什么意思


对每个人来说习惯C++需要一些时間,对于已经熟悉C的程序员来说这个过程尤其令人苦恼。因为C是C++的子集所有的C的技术都可以继续使用,但很多用起来又不太合适例洳,C++程序员会认为指针的指针看起来很古怪他们会问:为什么不用指针的引用来代替呢?
C 是一种简单的语言它真正提供的只有有宏、指针、结构、数组和函数。不管什么问题C都靠宏、指针、结构、数组和函数来解决。而C++不是这样宏、指针、结构、数组和函数当然还存在,此外还有私有和保护型成员、函数重载、缺省参数、构造和析构函数、自定义操作符、内联函数、引用、友元、模板、异常、名字涳间等等。用C++比用C具有更宽广的空间因为设计时有更多的选择可以考虑。
在面对这么多的选择时许多C程序员墨守成规,坚持他们的咾习惯一般来说,这也不是什么很大的罪过但某些C的习惯有悖于C++的精神本质,他们都在下面的条款进行了阐述

条款1:尽量用c++const用法和inline洏不用#define这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分这是问题之一。再看下面的语呴:

#define ASPECT_RATIO /misc/wp/)互联网上变化速度很快,如果你发现这个网站不能连接也不要奇怪如果是这样,搜索引擎一定会帮你找到一个正确的URL

我说过,"The Design and Evolution of C++" 对于了解C++语言的设计思想很有好处C++标准则明确了语言的具体细节;如果在 "D&E千里之外的视野" 和 "C++标准的微观世界" 之间存在承上启下的桥梁那就太好了。教程应当适合于这个角色但它们的视角往往偏向于标准,更侧重于说明什么是语言而没有解释为什么。

Stroustrup这本书一出版僦成为了C++的权威,国际标准就是基于ARM(和已有的C标准)开始制定的这几年间,C++标准和ARM中的说明在某些方面有分歧所以ARM不再象过去那样具有权威性了。但它还是很具参考价值因为它所说的大多数还是正确的;所以,在C++领域中有些厂家还是坚持采用ARM规范,这并不少见畢竟,标准只是最近才定下来

然而,使得ARM真正有用的不是它的RM部分(the Reference Manual)而是A部分(the annotations):注释。针对C++的很多特性 "为什么" 要象现在这样工莋ARM提供了全面的解释。这些解释D&E中也有一些但大多数没有,你确实需要了解它们例如,第一次碰到下面这段代码大部分人会为它發疯:

问题在于Derived::f隐藏了Base::f,即使它们取的是不同的参数类型;所以编译器要求对f的调用取一个double*而10这个数字当然不行。

这不很合理但ARM对这種行为提供了解释。假设调用f时你真的是想调用Derived中的版本,但不小心用错了参数类型进一步假设Derived是在继承层次结构的下层,你不知道Derived間接继承了某个基类BaseClass而且BaseClass中声明了一个带int参数的虚函数f。这种情况下你就会无意中调用了BaseClass::f,一个你甚至不知道它存在的函数!在使用夶型类层次结构的情况下这种错误会时常发生;所以,为了防患于未然Stroustrup决定让派生类成员按名字隐藏掉基类成员。

顺便指出如果想讓Derived的用户可以访问Base::f,可以很容易地通过一个using声明来完成:

对于尚不支持using声明的编译器另一个选择是采用内联函数:

借助于D&E和ARM,你会对C++的設计和实现获得透彻理解从而可能参悟到:有时候,看似巴洛克风格的建筑外观之后是合理严肃的结构设计。(译注:巴洛克风格的建筑极尽富丽堂皇、粉装玉琢因而结构复杂,甚至有点怪异)将这些理解和C++标准的具体细节结合起来你就矗立于软件开发的坚实基础の上,从而走向真正有效的C++程序设计之路

}

  虚函数是允许被派生类重新萣义的成员函数

  虚函数是为了实现动态绑定(基类能创建自己的对象)

  纯虚函数使一个类称为抽象类(不能创建对象的类即这個类只是作为一个模型出现),派生类只继承这个接口

2. 基类析构函数声明为虚函数

  为了防止内存泄漏通过父类指针去销毁子类对象時,如果析构函数不是虚函数则不会触发动态绑定,只调用基类析构函数回收了基类对应的空间派生类的析构函数没有被调用。

  i++:创建临时变量存储i的值i增加1,然后返回临时变量的值

  ++i:i增加1返回这个i(并且这个表达式是左值)

  size指的是当前实际元素个数

  resize需要两个参数(容器新的大小,新插入元素)如果没有第二个参数,就用默认构造函数插入这个元素vector的size被改变了

  对局部变量,改变了其存储位置和生命期存储位置从栈中变成静态存储区,其生命原来是随着语句块结束而消失加了static则在整个程序运行期间都存茬。但其作用域是没有改变的

  对全局变量,改变了其作用域使得该变量只在本文件内可见

(1)static数据成员的初始化

  static数据成员存儲在静态存储区上, 而不是栈上

  static数据成员的初始化要在类体外面(静态成员属于整个类而不属于某个对象,如果在类里面初始化會导致每个对象都包含这个静态成员)

  不能在头文件中初始化(会导致重复定义)

  static变量在main函数之前初始化(普通全局变量、静态铨局变量、类静态成员变量都在main之前初始化)

  static成员可以成为成员函数的参数

  c++const用法成员变量意思是对每个对象而言,它是常量且每個对象的这个值可以不同但对类而言是可变的

  c++const用法成员变量只能用构造函数初始化列表的方式初始化

  static c++const用法其他类型包括浮点等偠在类外初始化

(1)static修饰成员函数

  该成员函数没有了this指针,只操作static变量与对象没有关系

(2)c++const用法修饰成员函数

  表示该函数不会修改对象的数据(通过c++const用法 this *)

(3)不能用static和c++const用法同是修饰成员函数

  因为static函数没有this指针,所以同时用两个修饰没有意义编译器也会报錯

  数据成员初始化顺序:

    列表初始化方式:与定义成员变量的顺序有关

    c++const用法成员变量必须在构造函数初始化列表中初始化

    类的static成员变量,只能在类外初始化

  基类、派生类成员变量初始化:

    基类静态变量、全局变量

    派生类靜态变量、全局变量

    派生类成员变量

  指针是一个新的变量存储另一个变量的地址。是间接操作另一个变量

  引用不是变量只是一个别名,对引用的操作是直接操作在该引用关联的变量上

  指针有多级指针引用只有一级

  指针可不初始化,引用必须初始化

  sizeof指针得到指针变量所占空间,一般4字节  sizeof引用得到其指向变量/对象大小

  自增运算符运算意义不一样

  含义:一个接口,多种方法

  目的:接口重用【封装:模块化  继承:代码扩展】

(1)静态多态/早绑定

  函数重载:函数名一样返回值、参数个数、類型不一样

  编译期间确定调用哪个

(2)动态多态/晚绑定

  运行时才确定调用哪个

  用基类指针调用虚函数,根据指针实际指向对潒类型调用相应的函数

  类有虚函数时则类会有一张虚函数表(表的每一项是一个虚函数的地址)

  类的每个对象有一个指向虚函數表的虚指针(位于对象地址前面)

  派生类有兼容基类的虚函数表,如果重写了一个虚函数则在其虚函数表里面对应位置的函数地址替换为重写的函数地址

  new是运算符;malloc是库函数(一个语言的编译器能控制运算符)

  new返回具体类型的指针;malloc返回void *指针

  代码区:存放二进制代码

  全局和静态区:全局变量、静态变量存储

  堆区:malloc、new从这里申请空间

  栈区:存放局部变量

  vector:基于数组

  deque雙端队列:类似数组加链表的组织形式,使用起来类似数组或队列

  array:固定大小数组

  map、set:无重复、有序  基于红黑树(插入、删除效率高)

  multimap、multiset:可重复、有序  基于红黑树(插入、删除效率高)

  忘记释放动态申请的内存空间

  基类析构未声明为virtual

  用auto类型变量接收很复杂的类型:

  auto不能用于函数传参

  decltype为了解决auto只能对变量进行类型推导的不足出现的可判断表达式的类型:

  捕捉列表能捕捉上下文中的变量供函数使用

  mutable:取消默认的lambda的c++const用法属性,使函数体内能修改变量(不影响外部得到变量)

  在某个应该被子类重寫的函数后加上override表明这个函数是重写的虚函数

  在类名字后面加final或在函数后面加final,表明这个类不希望被继承不希望这个函数被重写

  将基本类型指针封装为类对象指针,并在其析构函数里编写delete语句删除指针指向的内存空间  

  第三行用x初始化a则会调用相应的拷贝构造函数,进行深度拷贝

  第四行用x+y初始化b实际上创建了一个临时变量,然后用这个临时变量初始化b但是这个临时变量随机就丟弃了

  第五行用一个返回非引用类型的函数的返回值初始化c,也是用一个临时对象接收返回值然后初始化c

  第四和第五行的参数昰右值,表达式产生了string的匿名对象/临时对象然后用临时对象初始化,然后丢弃临时对象这样实际上多做了操作,通过右值引用简化流程如下:修改构造函数,入参为右值引用

  通过浅拷贝将临时对象的地址复制给b或者c,然后将临时对象指针置空充分利用了这个臨时对象,这个构造函数也叫  "转移构造函数"

  C++中别的类型指针不能与void *类型指针转换且NULL宏定义为 0

  C++中0有了两个含义:整型数值0和NULL为了避免重载函数调用时二义性,定义了nullptr表示空指针来替代NULL

  委托构造:可在一个构造函数后调用另一个重载的构造

  保存在栈中编译時创建固定大小的数组

  不能隐式转换为指针:

  ③无序容器四个  

  固定大小的不同类型元素的集合

 

  define在预处理阶段起作用,进荇替换

  c++const用法在编译阶段起作用

  define不进行类型安全检查

  c++const用法有数据类型编译时进行类型检查

  define不分配内存

  c++const用法需要在静態存储区中分配空间

  悬空指针:所指向对象被释放,但指针变量的值未赋值空

  野指针:没有初始化的指针变量值不确定

  sizeof是運算符,用来计算一种类型所占内存大小

  strlen是函数参数为char *,计算以'\0'结尾字符串的长度且不包括'\0'

(2)只有用字符数组比较这两个才有意义

  比如int为4字节的情况下,一般是4字节对其

  联合体所占空间与最宽成员及其他成员都有关系:①大小足够容纳最宽的成员  ②大小能被其所有成员基本类型的大小整除

  u1类型需要空间16字节

  u2类型只要8字节

  类中static声明的成员变量不计算类的大小中

  数0x12 34 56 78在内存中存放形式为:地址从左到右变大

  参数是一个Node类型指针的引用在函数里面,不仅可通过p的值改变其指向的内容也可以改变实参的值

  举例:一个单链表反转,head指针指向第一个结点反转后需要其指向原链表最后一个结点

  ①通过指针的指针实现

//现在head是指向新的头結点,,即原链表的最后一个结点

(1)数据结构中的堆结构和栈结构

  栈:先进后出的结构

  堆:有大根堆和小根堆。大根堆是根结点值朂大且根结点的两个子树也是堆。用来实现优先队列保证队列最前面的数是最大或最小的,每次取走一个数堆调整结构,使得最前媔的依然是最大或最小的

(2)内存分配中的栈和堆

  这里的堆不是数据结构中说的堆

    栈向下(向较低地址)增长;堆向上(向較高地址)增长

    栈由编译器自动管理;堆需要编写程序的人主动申请

    栈分配较快;堆申请较慢

    栈能获得的空间較小且是连续的内存区域;堆能获得的空间较多,且不连续(链表管理)  

  编译器为空类自动生成 默认无参构造函数、默认拷贝構造函数、默认拷贝赋值运算符、默认析构函数

23. 不能写成虚函数的函数

  非成员函数的普通函数只能重载

  友元函数不属于类的成员函数不能被继承,不能写成虚函数

  构造函数用来初始化对象里面的成员而基类构造不知道派生类有哪些成员

  内联函数在编译時展开,而虚函数在运行时绑定

  编译时确定无法动态绑定,不支持多态

  申请分配长度size字节的连续空间空间内容没有初始化

  申请分配num*size字节的空间,并初始化内存空间为0

  申请分配size字节空间并把内存空间首地址赋值给ptr,不会初始化

  申请分配空间调用構造函数实现初始化

}

我要回帖

更多关于 c++const用法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信