一、类的定义
类有点类似c语言的结构体是一种自定义类型,但类里面除了定义一些成员变量外还有方法(成员函数),在访问的时候要指定类域。
在类定义时首先用一个class关键字,在后面接着类的名字,然后使用{ }在花括号里面定义成员变量和成员函数,最后需要在花括号外加分号,如下:
class Stack{ void Init(int n = 4) { arr = (int*)malloc(sizeof(int) * n); if (nullptr == arr) { perror("malloc申请空间失败"); return; } capacity = n; size = 0; } //...... int* arr; size_t size; size_t capacity;};
这里calss也可以替换成struct,在类里面的函数默认都为内联函数,当然它不一定都展开具体还取决于编译器。
二、访问限定符
在定义类的时候通常会用一些关键字来限定类成员的访问,访问限定符有public,private,protected。
public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private的具体区别这里先不讲解。访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到}即类结束。class定义成员没有被访问限定符修饰时默认为private,struct默认为public。⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public。class Stack{public: void Init(int n = 4) { arr = (int*)malloc(sizeof(int) * n); if (nullptr == arr) { perror("malloc申请空间失败"); return; } capacity = n; size = 0; } //......private: int* arr; size_t size; size_t capacity;};
三、类域
类成员受到类域限制,在访问的时候需要指明类域,像命名空间一样使用::指明类域,如果一个函数声明在类里,定义在类外,那么在定义函数的时候就得使用::指明类域,如下:
class Stack{public: void Init(int n = 4); //......private: int* arr; size_t size; size_t capacity;};void Stack::Init(int n = 4){ arr = (int*)malloc(sizeof(int) * n); if (nullptr == arr) { perror("malloc申请空间失败"); return; } capacity = n; size = 0; }
当然访问类域内的函数通常都使用类对象加点( . ) 操作符去访问,如下:
四、实例化
类就像是一栋房子的图纸,而用类去定义对象就类似使用图纸建造房子,这个过程就叫做实例化。
类是不占用内存的,只有实例化后才会占内存,就像只有把图纸建造出房子后才占用地盘一样。而那么计算一个对象的内存呢?
五、对象的大小
对象与对象之间主要区别在于成员变量的值,而同一个类的所有对象的成员函数都是一样的,所以成员函数并不储存在对象里面,只用考虑成员变量所占的内存,而成员变量占用的内存和结构体的内存计算方法一样,因为它们都存在内存对齐。需要注意的是静态成员并不是储存在对象里面(和成员函数同理),而是储存在静态区,不能算入。在类里面的静态成员与在全局申请的静态成员区别在于类成员受到类域的限制。
如果一个类里面一个成员变量都没有那么按上面逻辑来说它实例化出来的对象占的空间应该是0,而对于这种情况编译器做了特殊处理,它所占的空间为1字节。
六、this指针
类中有Init等成员函数,函数体中没有关于不同对象的区分,那当对象d1调⽤Init和其它函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?在这里C++给了⼀个隐含的this指针解决这⾥的问题。
编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。⽐如Stack类的Init的真实原型为, void Init(Stack* const this, int n=4)。 C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显示使⽤this指针。
类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给size赋值, 可以看做this->size = 0;