C++编程理论学习笔记
1.变量:
变量的值都存储在内存中。内存中每个单元都有一个唯一的编号,就是单元的地址,变量在运行时占据内存单元互不相同的地址,C++的目标代码靠地址来区别不同的变量。
2.表达式:
虽然内存是存储c++变量的主要场所,但不可能一切读写操作都通过在内存中进行,事实上,CPU的大部分读写操作都是对寄存器进行的。
寄存器从内存中取得变量值,存储每一步运算的中间结果,最后返回给表达式。
3.函数调用:
首先计算实参列表中各个表达式的值(每个实参都是一个表达式),然后主调函数暂停,执行被调函数,形参的初值就是实参表达式的结果。
返回值会先复制到一个无名的临时对象,然后再把临时对象的值传给表达式之后临时对象自动消失。所以返回值不能是引用类型因为函数一结束对象就消失了。
4.引用传递:
引用是一种特殊类型的变量,可以被认为是另一个变量的别名,用引用作为形参,在函数调用时发生的参数传递称为引用传递,俗称“传引用”。
传引用与传值不同,其形参的初始化不在类型说明时进行,而是在执行主调函数中的表达式时才获得内存空间,这样引用类型的形参就通过实参来初始化,成为实参的一个别名,于是对形参的操作直接作用于实参。
5.运行栈:
全局变量都有唯一的地址,但局部变量不行,如果为局部变量分配唯一的地址,不仅降低空间的利用率,更重要的是相同名称的局部变量可能有不同的值,这些值必须同时保存在内存中又不能相互影响,所以不能为局部变量分配唯一的地址。
而函数的形参的情形与局部变量相似,因此它们都需要存储在特殊的内存空间—-运行栈中。
运行栈与数据结构中的栈有所区别,在数据结构中,栈是一种容器,后入先出。
但运行栈是一段实际存在的内存空间,与存储全局变量的内存空间没有什么不同,只是寻址的方式不同而已。
运行栈的数据分为一个一个的栈帧,每个栈帧对应一次函数调用。通过esp寄存器记录栈顶,ebp记录开始调用时栈指针的位置,函数调用时栈帧压入运行栈,返回时压出,与栈的后入先出是一样的。
6.内联成员函数:
相当简单的成员函数才把它声明为inline内联函数,也不是声明了内联函数后编译器一定会把它当作内联函数,内联成员函数没有被调用,只是在编译时被插入到每一个调用它的地方。尽量使用显式声明。
7.防卫式声明:
#ifndef __CLASS__
#define __CLASS__
…//class
#endif
防止类重复定义
8.前向引用声明:
当两个类相互组合或相互调用时,需要后一个类在前面有一个前向引用声明,告诉前一个类有这么一个类存在,这样编译器就不会认为是错误,相当于函数原型声明。
class A; //声明类名即可
9.复制构造函数:
用同个类的对象去复制出此类的一个新的对象,复制构造函数形参是本类对象的引用,只有把对象用值传递时才会调用复制构造函数,如果传递引用,则不会调用复制构造函数。
class a(…);
class b(a);
class b=a;
这两种方式都会调用复制构造函数
当我们没有定义复制构造函数时,系统自动生成隐式的复制构造函数,直接将原对象的数据成员值一一赋给新对象中对应的数据成员。
但是当类的数据成员中有指针类型时,默认复制构造函数实现的是浅复制,会带来数据安全隐患。
浅复制就是直接复制地址,没有去申请内存空间,比如指针直接把地址复制给了新对象,两者都指向同一段内存,无论谁修改都会影响另一方,数据没有独立性,而且,在程序结束时会自动调用两次析构函数,分别释放两对象的同一个内存空间,必然引起运行错误!
所以有指针类型的成员时一定要写自己的复制构造函数,实现深复制–申请内存、再把元素复制过来。
10.初始化列表
在构造函数中才有的语法,常用。
fun(param1 a,param2 b):one(a),two(b){}
相当于
fun(a,b){
one=a;
two=b;
}
one,two分别是两个内嵌对象,可以多个
11.UML类图关系
12.参数传递原则
(1)数组传指针
(2)结构:不修改则加Const ,小则传值,大传引用或指针;
(3)类:传引用,不修改则加Const
(4)内置数据类型:不修改传值,修改传指针