C++
C
- {}中定义变量只在{}中存在
1. 面对对象
- Object = Entity 对象等于实例,在程序语言中就是变量
- Class(类)定义了 Object(对象)的属性,对象是一个类的实例
2. 头文件
- ::区域解析符
- .h 头文件,声明类
- .cpp
- declarations 声明 extern、函数的原型、类、结构都是声明
- definitions 定义 变量的称为定义,
- #include 编译预处理,直接将要导入的类文本插入到目标文件中
- #include “xx.h” 在当前目录中寻找
- #include
在系统目录中寻找 - #include
与 #include 一致
- .h文件中只声明不定义,是为了避免重复定义
- 标准头文件结构
- #ifndef HEADER_FLAG
- #define HEADER_FLAG
- #endif
- 一个头文件中只放一个类的声明,对应的源代码文件用相同的前缀,后缀cpp
- 只能include .h文件,不能是 .cpp 文件
3. 成员变量
- 成员变量(field),参数(parameter),本地变量(local variables)
- 在.h中的成员变量并不真实存在,只是进行了声明
- 类是抽象的不存在实体,成员变量(属性)属于对象不是属于类的,函数(方法)是属于类的不属于对象
- 类的函数只存在于一个,不同的对象调用的是同一个函数,调用的时候相当于把对象的地址传入到函数当中
- 不同的对象调用一个函数时,该函数知道是哪一个对象在调用自己,实际上是通过隐藏变量 this 指向当前的对象,this->i
4. 构造和析构
- 构造函数
- 函数名字和类的名字相同
class Tree{ int height; public: Tree(int initialHeight)l; ~Tree(); void grow(int years); void printsize( ) } Tree::Tree(int initialHeight){ height = initialHeight } Tree t(12)- 没有参数的构造函数称为 default constructor
struct Y { float f; int i; Y(int a); } Y y1[] = {Y(1), Y(2), Y(3)} //可以 Y y2[2] = {Y(1)}; // 错误,缺失构造函数的参数
5. 动态内存
- 之前都是本地变量,还可以动态申请内存
- new,delete
1.for 循环内定义的变量的生命周期
for中定义的变量,编译器编译后,是存放在栈空间上的一个临时内存地址
每单次循环结束程序都会跳出循环体的作用域,循环体内的局部变量都被释放;下一次循环重新进入循环体,里边的每个局部变量和对象都重新构造。
每次定义的 n,其 生命周期只有一次循环的时间(比如 i=0的那次循环过后,Listnode的内存空间就被回收了,也就不妨碍 i=1时对Listnode的定义了)
for (int i= 0; i < 5; i++) {
Listnode n;
}
2.内存的四种分区
- 栈区(stack):编译器自动分配和释放的,主要存储的是函数的参数值,局部变量等值。发生函数调用时就为函数运行时用到的数据分配内存,函数调用结束后就将之前分配的内存全部销毁。所以局部变量、参数只在当前函数中有效,不能传递到函数外部。栈内存的大小和编译器有关,编译器会为栈内存指定一个最大值,在 VC/VS 下,默认是 1M。
- 堆区(heap):动态分配。一般由程序员分配和释放(动态内存申请malloc与释放free),需要手动free。否则会一直存在,若程序员不释放,程序结束时可能由操作系统回收。
- 全局区(静态区)(static):静态分配。全局变量和静态变量的存储是放在一块的,该区域在程序结束后由操作系统释放。
- 代码区:通常用来存放程序执行代码(包含类成员函数和全局函数及其他函数代码),这部分区域的大小在程序运行前就已经确定,也有可能包含一些只读的常数变量,例如字符串变量。
new的作用
在实际的编程中,实际要处理的数据数量在编程时无法确定,所需的内存空间大小无法确定时,除了定义“尽可能大的空间”的方法,还有就是动态内存分配。此种内存分配是在程序运行中进行的,而不是在编译时就确定的,因此称为“动态内存分配”。
在 C++ 中,通过 new 运算符来实现动态内存分配。
new开辟的空间在堆上。
当在局部函数中new出一段新的空间,该段空间在局部函数调用结束后仍然能够使用,可以用来向主函数传递参数。
new的使用格式,new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。
6. 访问限制
- public
- private 类的所有成员函数可以访问,直接使用变量名例如x即可访问。私有是对类来说的,而不是对象,同一个类的对象之间可以互相访问私有的成员变量。
class A{ private: int i; int *p; public: A(){p=0} ~A()(if (p) delete p;) void set(int ii){i = ii;} void f(){p = new int;} void g(A* q){cout << q->i <<endl;} }; int main(){ A* p = new A[10]; for (int i=0; i <10; i++) p[i].set(i); A b; b.set(100); p[0].g(&b); delete[] p } - protected
7. 初始化列表
除了在构造函数中初始化成员变量,还可以用初始化列表(initialization list)
class A{ private: int i; int *p; public: A(){p=0} };class A{ public: A():p(0) };- 初始化列表是早于构造函数的,构造函数的初始化相当于先初始化得到成员变量p再赋值
class Point{ private: const float x, y; Point(float xa = 0.0, float ya = 0.0) : y(ya), x(xa) {} }
8. 继承(inheritance)
- 继承可以共享父类的成员变量和函数和接口(interface)
- 父类(parent class),子类(child class)
class A { public: A():i(0) {} private: int i; } class B: public A{} - 子类无法访问父类的private,但可以访问protected
9. 函数重载
- 默认参数 int harpo(int n, int m = 4, int j = 5);
- 默认参数写在.h里的,.cpp里不能写