- c++域:局部域、全局域、命名空间域、类域(后两个域不影响生命周期)。Namespace只能定义在全局,且可以嵌套定义。同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
- 命名空间展开:using using namespace yy;(全部展开) using namespace yy::a(部分展开),展开后,可在局部空间直接使用。
- 默认参数:默认参数从右往左给,传参时从左往右传。(从左到右一一对应),默认参数只能在函数声明的时候使用。
- 引用:1、引用类型必须和引用实体是同种类型的; 1. 引用在定义时必须初始化 2. 一个变量可以有多个引用 3. 引用一旦引用一个实体,再不能引用其他实体。
- 隐式类型转换时,会生成一个中间变量,有常量属性,所以要用常引用。表达式作为引用主体,也具有常属性,需要常引用
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
- 如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用 引用返回,如果已经还给系统了,则必须使用传值返回。
- 引用和指针的不同点: 1. 引用概念上定义一个变量的别名,指针存储一个变量地址。 2. 引用在定义时必须初始化,指针没有要求 3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体 4. 没有NULL引用,但有NULL指针 5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节) 6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小 7. 有多级指针,但是没有多级引用 8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 注意:引用和指针在汇编指令层面上完全一致。
- 内联函数:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销(用函数体替换函数调用),内联函数提升程序运行的效率。
- inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会 用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运 行效率。 2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建 议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不 是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
- inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址 了,链接就会找不到。
- 在c++中,尽量使用nullptr来表示空指针,它可以接受任意类型的指针,但不接受整形。
- 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为 是默认构造函数。即,不用传参的构造函数是默认构造函数。
- 编译器默认生成的构造函数会对内置成员函数初始化为随机值(视编译器而定),注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在 类中声明时可以给默认值。
- 析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
- 析构函数名是在类名前加上字符 ~。 2. 无参数无返回值类型。 3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载 4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。5.内置成员变量不需要析构,在程序运行结束后,将自动销毁。 6.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如 Date类;有资源申请时,一定析构,否则会造成资源泄漏,比如Stack类。
11。拷贝构造函数// Date(const Date& d) // 正确写法
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数第一个必须是类类型对象的引用,其他的必须是带缺省值的参数。使用传值方式编译器直接报错, 因为会引发无穷递归调用。(c++规定传值传参和传值返回时,会调用一次拷贝构造函数)。
- 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定 义类型是调用其拷贝构造函数完成拷贝的。
- 注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
- 赋值运算符重载
- 赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值 , 检测是否自己给自己赋值
返回*this :要复合连续赋值的含义,this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
例如:Date& operator=(const Date& d) (第一个参数是隐式的this)
{
If(this != &d)
{
_year=d._year;
}
Return *this;
}
- 赋值运算符只能重载成类的成员函数不能重载成全局函数。
- 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注 意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符 重载完成赋值。
- 前置++和后置++重载
- 代码对比:
前置(先++后使用)
Date& operator++() (在类内实现,默认传递一个this)
{
_day += 1;
return *this;
}
后置(先使用后++)
Date operator++(int)
{
Date temp(*this);
_day += 1;
return temp;
}
注意:前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载 C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器 自动传递 // 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存 一份,然后给this+1 // 而temp是临时对象,因此只能以值的方式返回,不能返回引用
- 初始化列表
- 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
- 类中包含以下成员,必须放在初始化列表位置进行初始化: 引用成员变量 const成员变量 自定义类型成员(且该类没有默认构造函数时)
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量, 一定会先使用初始化列表初始化。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后 次序无关
- static成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明 3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员 5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
16.友元
友元函数可访问类的私有和保护成员,但不是类的成员函数 友元函数不能用const修饰 友元函数可以在类定义的任何地方声明,不受类访问限定符限制 一个函数可以是多个类的友元函数 友元函数的调用与普通函数的调用原理相同
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性,不具有传递性。
友元关系不能继承
17.内存管理
1.new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是 系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。
2.实现原理
内置类型:
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是: new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申 请空间失败时会抛异常,malloc会返回NULL。
自定义类型:
new的原理 1. 调用operator new函数申请空间(底层还是malloc)
2. 在申请的空间上执行构造函数,完成对象的构造
delete的原理 1. 在空间上执行析构函数,完成对象中资源的清理工作
- 调用operator delete函数释放对象的空间
new T[N]的原理
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对 象空间的申请
- 在申请的空间上执行N次构造函数
delete[]的原理
- 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
- 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释 放空间
- 对于内置类型,new[],使用delete 可以,不会内存泄漏,但不建议,对于自定义类型,必须使用delete[],否则会程序崩溃。
- New[n]会额外申请4个字节,用来存储n这个整型值,告诉编译器需要执行n次构造函数与析构函数。
18.模板
1.格式:template<typename T1, typename T2,......typename Tn> T为类型
2.函数模板实例化:用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
template<typename T>
T Add(const T& i, cosnt T& j)
{ return i+j;}
Int main()
{ int a=10;
Double b=20;