1、预处理器封套:
#ifndef XXX_H #define XXX_H ... class xxx{ ... } ... #endif 复制代码
如果没有文件包含此头文件,XXX_H被定义并包含这个头文件;如果已经包含,则不再定义和包含。
为了防止多次包含同一个头文件,尤其包含套包含的时候。注意命名要大写和下划线。
2、对象的sizeof
sizeof一个对象得到的是所有数据成员的大小。
因为函数不存储在对象中,而是由编译器创建独立于所有对象的函数副本,所有对象共享函数副本。
3、访问对象数据成员和成员函数
对象名或对象引用的情况
a.b
a.b()
对象指针的情况
aPtr -> b
aPtr -> b()
4、工具函数
工具函数即private函数
5、析构函数
~类名()
在对象被撤销时被调用,某种意义上是与构造函数互补。
class Time{ Time(...){...} ~Time(){...} } 复制代码
注意:
不接收任何参数,不返回任何参数,void也不行。
一个类只能有一个析构函数,不允许重载。
6、对象传参
当对象作为参数或返回值时是传值参数,即传的是拷贝。
所以当要使用真正对象需要传引用或指针。
7、const对象\函数
声明对象 (注意位置):
void name() const {....}
对象声明const不能被修改,不能调用非const的成员函数。
成员函数声明const不能修改对象,同样不能调用非const的成员函数。
(1)可以对const成员函数进行非const重载。编译器根据对象性质选择相应函数,
const对象调用const函数;非const对象调用非const函数
(2)构造、析构函数不能声明const。
8、成员初始化器
int count; const in num; Time(int i, int j):count(i),num(j){...} 复制代码
所有数据成员都可以用成员初始化器来初始化,如上面的形式。
但是const数据成员和引用的数据成员必须使用成员初始化器进行初始化,不能通过赋值初始化。
(1) 成员初始化器在构造函数体执行前执行。
(2)建议将所有不修改对象的函数声明为const。
9、组成
即数据成员是一个其他类的对象。
如果构造函数没有初始化某个成员,那么会隐式的调用该成员的默认构造函数。如果该成员的类没有默认构造函数,编译报错。
10、friend函数和类(友元)
class A{ friend class B; friend void b(...); } 复制代码
友元可以访问原类中的非public成员和函数。
(1)友元关系不传递,不对称。
(2)友元函数不是成员函数
(3)友元最好在数据成员及函数之前声明。
(4) 友元模板类或模板函数的情况,需要提前定义,否则报错,如:
template<typename T> class B; class A{ friend class<T> B; } 复制代码
(5) 友元是非模板类的成员函数,也需要提前定义。
10、this指针
因为是指针,所以:this -> x 或 (*this) .x
11、动态内存管理(new\delete)
Time time; 或 int num[24]; 这样在定义时需要将所有内存分配(所有成员内存或所有元素内存),即使未使用到,且不能改变。
使用动态内存管理实际上是在 自由存储区分配内存区域,通过delete释放。
Time *timePtr = new Time(....); delete timePtr; int *numsPtr = new int[24]; delete [] numsPtr; 复制代码
(1)释放时先调用析构函数,再回收内存。 数组释放时不加“[]”只调用第一个元素的析构函数。
(2)不释放会造成内存泄漏
(3)在编译时创建数组,大小必须用常量;而动态分配是可以使用任何表达式,如new int[a + b];
(4)动态分配一个对象数组时,会使用对象的默认构造函数初始化
(5)delete之后最好将指针设为0,如numsPtr=0。因为回收后内存空间中的信息还在,只是没有关系了,如果不注意访问了,会导致极端诡异无法复现的问题
(6)尤其注意循环中要使用new,否则会出错,如下:
for (int i = 0; i < 5; i++) { Node<int> node(i); Node<int> *ptr = &node; } 复制代码
运行时会发现每次循环ptr指针指向的地址是不变的,也就是说所有的循环一致用一个Node对象而不是每次新建,这样会导致逻辑错误。改成new动态分配后,每次循环都是新的对象。
12、static
static数据成员只能被初始化一次。
int或枚举类型的const static数据成员可以在类定义中初始化;所有其他类型的数据成员必须在文件作用域(类定义外)定义并初始化。
xxx.h class{ ... private: static int a; ... } xxx.cpp ... int a = 1; ... 复制代码
(1) 在.cpp文件中定义初始化static数据成员时不能声明static,应该在.h中声明为static。
(2)如果成员是对象且有默认构造函数,可以不初始化。
(3)public static数据成员在类外部使用: 没有任何对象时Time::cout;有对象时time.count。
(4) 在static函数中不能使用this,否则编译错误。static函数不能被声明称const。
13、代理类
使用头文件虽然可以隐藏实现细节,但是依然暴露private数据成员或函数。
使用代理类,只有一个private成员,即被代理类的对象指针。