缺省参数:静态绑定
虚函数的替代设计:non-virtual-interface(NVI) --effective c++
通过调用public的non-virtual成员函数,调用private的virtual函数。形成一种装饰器/wrapper的效果
C++前置声明
如果B只是保留A的指针或引用,并不用A的成员函数或变量,可以无需包含A的头文件,减少编译依赖
sizeof
#pragma pack(8)
struct s1{
short a; // +2
int b; // 对齐规则为min(8,4) = 4,前面补空+2;+4
};//sizeof(s1) = 8
struct s2{
char c; // +1
s1 d; // 对struct来说,以struct内的最大元素对齐,即4,前面补空+3;+8
long long e;// 前面补空+4,+8
};//sizeof(s2) = 24
#pragma pack()
如果有pragma pack(n),则对齐的规则为min(n,sizeof(type))
#pragma pack(4)
struct s1{
short a; // +2
int b; // 对齐规则为min(4,4) = 4,前面补空+2;+4
};//sizeof(s1) = 8
struct s2{
char c; // +1
s1 d; // 对struct来说,以struct内的最大元素对齐,即4,前面补空+3;+8
long long e;// min(4,8)=4,按照4对齐,所以不补空,+8
};//sizeof(s2) = 20
#pragma pack()
构造函数、析构函数都不采用动态联编,调用虚函数运行的是构造函数或者析构函数本身类型的方法。
拷贝构造函数:
形式如A::A([const] A& obj){}
或者可以带默认值的参数
调用场景:对象以值的方式作为参数传入方法,对象以值传递方式从函数返回(跟编译器相关,-fno-elide-constructors强制调用),对象需要另外一个对象初始化。
赋值构造函数:
A& A::operator=(const A& obj){}
需要校验自赋值问题,可以判断*this;也可以保留原有obj的指针,new完之后再释放;也可以采用swap的方式。
移动构造函数:
形式如A::A(A&& obj){}
场景:用a初始化b,且用完之后a就不再使用,需要在函数体中将a中的空间置为nullptr。
隐藏:
如果派生类的函数名与基类函数名相同,但是参数不同,不管有无virtual,基类的函数被隐藏。
如果派生类函数与基类函数同名,参数相同,但是没有virtual,基类函数被隐藏。
可以在子类中使用using 声明式,显示父类中被遮蔽的函数
虚函数表:
对存在虚函数的对象,编译器会生成一个虚表,存放每个虚函数的地址,采用虚表指针vptr进行索引。构造函数中进行虚表的创建和虚表指针的初始化,所以在构造函数中不能调用虚函数,因为结果是不可控的。
含虚函数的编译:采用晚绑定方式,编译时不确定具体调用的函数,调用时根据对象指针进行查找并调用。
class、struct
class默认访问权限是private,struct默认是public,friend可以访问朋友类里所有private的成员和方法
static关键字:
1、隐藏声明在某个文件中的变量(非类变量)。static声明的变量跨文件找不到。
2、因为static变量存储在静态存储区,所以会程序运行时初始化,保持变量内容持久。
3、static声明的全局变量放在源文件而不是头文件,防止static变量的污染。(如果定义在头文件中,在两个编译单元中的static变量的static成员并不指向同一块内存地址)
4、静态成员函数不能直接访问类的私有成员变量,但是可以通过传入一个类成员的指针来解决。
volatile关键字:
类型修饰符,一种语言级别的内存屏障,编译器对该变量访问的代码不进行优化,提供对特殊地址的稳定访问。系统总是从内存中读取数据。
多用于:多任务环境下的共享标志;但是并不能保证多线程的并发性。
extern关键字:
该变量、函数在别处定义,在此处引用;可以不用包含头文件
extern “C”:可以单一语句、复合语句、头文件。按照C语言的规则翻译函数名,
变量:extern--声明,其他--定义。
.h文件中声明的全局变量,只能在同一个.cpp文件中定义
const关键字:
只能用于本编译模块,但是可以与extern连用,应用于其他编译模块中。
BSS、DATA、堆栈:
初始化为0或未初始化的全局或静态值都存在BSS段中。