当前位置: 首页 > news >正文

绩溪做网站wordpress下载页面插件

绩溪做网站,wordpress下载页面插件,企业网站打不开了,seo关键词推广公司目录 一.命名空间 1.命名空间定义 2.命名空间使用 二.C输入输出 三.缺省参数 四. 函数重载 五.引用 1.常引用 2.传值、传引用效率比较 3.引用和指针的区别 4.引用和指针的不同点: 小知识点: 六.内联函数 七.auto关键字(C11) 1.auto的使用细则 八.基于范围… 目录 一.命名空间 1.命名空间定义 2.命名空间使用 二.C输入输出 三.缺省参数 四. 函数重载 五.引用 1.常引用 2.传值、传引用效率比较 3.引用和指针的区别 4.引用和指针的不同点: 小知识点: 六.内联函数 七.auto关键字(C11) 1.auto的使用细则 八.基于范围的for循环(C11) 1.范围for的使用条件 九.空值nullptr 十.类与对象 1.class与struct 2.类的定义 类的两种定义方式 1. 声明和定义全部放在类体中 2. 类声明放在.h文件中,成员函数定义放在.cpp文件中 ①模版的情况下 ​编辑3.成员变量命名规则的建议 3.类的访问限定符及封装 1 访问限定符 2.访问限定符说明 访问限定符在继承中 3.C中struct和class的区别是什么 4.封装 4.类的作用域 5.类的实例化 6.类对象模型  1 如何计算类对象的大小结构体内存对齐 7.this指针 8.类的6个默认成员函数  1.构造函数 内置类型和自定义类型在构造中 小知识点: 2.析构函数 内置类型和自定义类型在析构中 小知识点析构顺序 析构顺序和次数 3.拷贝构造函数 内置类型和自定义类型在拷贝构造 9.赋值运算符重载 全局的operator 类内的operator 内置类型和自定义类型在赋值运算符重载 小知识点: 日期类的实现(已经弄完了)  10.初始化列表 成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关小知识点: 11.static成员explicit关键字 小知识点: ​编辑 12this指针 this指针的特性 this在哪里 13.友元函数和友元类(Date里有) 友元类 十一.内存管理 C语言中动态内存管理方式malloc/calloc/realloc/free C内存管理方式 new和delete操作自定义类型 operator new与operator delete函数 new和delete的实现原理 内置类型 自定义类型 定位new表达式(placement-new) 了解 malloc/free和new/delete的区别 内存泄漏 小知识点new和delete【】匿名对象和重复释放 十二.函数模版和类模版 函数模板 函数模板概念 函数模板格式 函数模板的实例化 重要例子 类模版 动态顺序表 类模板的实例化 十三.string vector list stack queue priority_queue 反向迭代器 函数模板特化 类模板特化 全特化 偏特化 模板的分离编译 模板总结 知识点总结(易遗漏): c_str 仿函数 一.命名空间 在C/C中变量、函数和后面要学到的类都是大量存在的这些变量、函数和类的名称将都存 在于全局作用域中可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化 以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的比如后面vestor和list等等的模拟实现。 1.命名空间定义 定义命名空间需要使用到namespace关键字后面跟命名空间的名字然后接一对{ }即可{ }中即为命名空间的成员。 1.命名空间中可以定义变量/函数/类型 2.命名空间可以嵌套, 3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。一个工程中的test.h和上面test.cpp中两个N1会被合并成一个,代码例子 test.cppnamespace N1{int a;int b;int Add(int left, int right){return left right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}} } test.hnamespace N1{int Mul(int left, int right){return left * right;} }注意一个命名空间就定义了一个新的作用域命名空间中的所有内容都局限于该命名空间中 2.命名空间使用 命名空间的使用有三种方式 1.加命名空间名称及作用域限定符 int main() {printf(%d\n, N::a);return 0;     }2.使用using将命名空间中某个成员引入 using N::b;int main() {printf(%d\n, N::a);printf(%d\n, b);return 0;     }3.使用using namespace 命名空间名称 引入 using namespce N;int main() {printf(%d\n, N::a);printf(%d\n, b);Add(10, 20);return 0;     } 二.C输入输出 说明 1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时必须包含 iostream 头文件以及按命名空间使用方法使用std。 2. cout和cin是全局的流对象endl是特殊的C符号表示换行输出他们都包含在包含 iostream 头文件中。 3. 是流插入运算符是流提取运算符。 4. 使用C输入输出更方便不需要像printf/scanf输入输出时那样需要手动控制格式。 C的输入输出可以自动识别变量类型。 5. 实际上cout和cin分别是ostream和istream类型的对象和也涉及运算符重载等知识 这些知识我们我们后续才会学习所以我们这里只是简单学习他们的使用。后面我们还有有 一个章节更深入的学习IO流用法及原理。 注意早期标准库将所有功能在全局域中实现声明在.h后缀的头文件中使用时只需包含对应 头文件即可后来将其实现在std命名空间下为了和C头文件区分也为了正确使用命名空间 规定C头文件不带.h旧编译器(vc 6.0)中还支持格式后续编译器已不支持因 此推荐使用std的方式。 #include iostreamusing namespace std;三.缺省参数 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时如果没有指定实 参则采用该形参的缺省值否则使用指定的实参。 代码例子 void Func(int a 0) {coutaendl; }int main() {Func();     // 没有传参时使用参数的默认值Func(10);   // 传参时使用指定的实参return 0; }缺省参数分类.全缺省参数.半缺省参数 void Func(int a 10, int b 20, int c 30)void Func(int a, int b 10, int c 20)注意 1. 半缺省参数必须从右往左依次来给出不能间隔着给 2. 缺省参数不能在函数声明和定义中同时出现,代码例子 //a.h   void Func(int a 10);     // a.cpp void Func(int a 20) {}   // 注意如果生命与定义位置同时出现恰巧两个位置提供的值不同那编译器就无法确定到底该用那个缺省值。 3. 缺省值必须是常量或者全局变量 4. C语言不支持编译器不支持 四. 函数重载 函数重载是函数的一种特殊情况C允许在同一作用域中声明几个功能类似的同名函数这 些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同常用来处理实现功能类似数据类型 不同的问题。 1、参数类型不同 int Add(int left, int right) {cout int Add(int left, int right) endl;return left right; } double Add(double left, double right) {cout double Add(double left, double right) endl;return left right; }2、参数个数不同 void f() {cout f() endl; }void f(int a) {cout f(int a) endl; }3、参数类型顺序不同  void f(int a, char b) {cout f(int a,char b) endl; }void f(char b, int a) {cout f(char b, int a) endl; }五.引用 引用不是新定义一个变量而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空 间它和它引用的变量共用同一块内存空间。 类型 引用变量名(对象名) 引用实体 注意引用类型必须和引用实体是同种类型的 1. 引用在定义时必须初始化 2. 一个变量可以有多个引用 3. 引用一旦引用一个实体再不能引用其他实体 1.常引用 void TestConstRef() {const int a 10;//int ra a;   // 该语句编译时会出错a为常量const int ra a;// int b 10; // 该语句编译时会出错b为常量const int b 10;double d 12.34;//int rd d; // 该语句编译时会出错类型不同const int rd d; } 注意如果函数返回时出了函数作用域如果返回对象还在(还没还给系统)则可以使用 引用返回如果已经还给系统了则必须使用传值返回。代码例子 int Add(int a, int b) {int c a b;return c; } 会出错 2.传值、传引用效率比较 以值作为参数或者返回值类型在传参和返回期间函数不会直接传递实参或者将变量本身直接返回而是传递实参或者返回变量的一份临时的拷贝因此用值作为参数或者返回值类型效率是非常低下的尤其是当参数或者返回值类型非常大时效率就更低。 3.引用和指针的区别 在语法概念上引用就是一个别名没有独立空间和其引用实体共用同一块空间。 在底层实现上实际是有空间的因为引用是按照指针方式来实现的。 4.引用和指针的不同点: 1. 引用概念上定义一个变量的别名指针存储一个变量地址。 2. 引用在定义时必须初始化指针没有要求 3. 引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何 一个同类型实体 4. 没有NULL引用但有NULL指针 5. 在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32 位平台下占4个字节) 6. 引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小 7. 有多级指针但是没有多级引用 8. 访问实体方式不同指针需要显式解引用引用编译器自己处理 9. 引用比指针使用起来相对更安全 小知识点: 的指向不可以被改变  引用做返回值可以提高效率减少拷贝  做返回值返回的内容出作用于必须还存在静态变量就还在数组类型的也在 六.内联函数 概念:以inline修饰的函数叫做内联函数编译时C编译器会在调用内联函数的地方展开没有函数调 用建立栈帧的开销内联函数提升程序运行的效率。 inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同 一般建议将函数规模较小(即函数不是很长具体没有准确的说法取决于编译器内部实现)、不 是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性。 inline不建议声明和定义分离分离会导致链接错误。因为inline被展开就没有函数地址 了链接就会找不到。 宏的优缺点 优点 1.增强代码的复用性。 2.提高性能。 缺点 1.不方便调试宏。因为预编译阶段进行了替换 2.导致代码可读性差可维护性差容易误用。 3.没有类型安全的检查 。 C有哪些技术替代宏 1. 常量定义换用const enum 2. 短小函数定义 换用内联函数 七.auto关键字(C11) std::mapstd::string, std::string::iterator it m.begin(); 等价于 auto iterator itm.begin() 注意 使用auto定义变量时必须对其进行初始化在编译阶段编译器需要根据初始化表达式来推导auto 的实际类型。因此auto并非是一种“类型”的声明而是一个类型声明时的“占位符”编译器在编 译期会将auto替换为变量实际的类型。 1.auto的使用细则 1. auto与指针和引用结合起来使用 用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时则必须 加 2.在同一行定义多个变量 当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译 器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。 八.基于范围的for循环(C11) 对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误。因 此C11中引入了基于范围的for循环。for循环后的括号由冒号“ ”分为两部分第一部分是范 围内用于迭代的变量第二部分则表示被迭代的范围。 注意范围必须明确 int array[] { 1, 2, 3, 4, 5 };for(auto e : array)加可以改变值e * 2;for(auto e : array)cout e ;与普通循环类似可以用continue来结束本次循环也可以用break来跳出整个循环。 1.范围for的使用条件 1. for循环迭代的范围必须是确定的 对于数组而言就是数组中第一个元素和最后一个元素的范围对于类而言应该提供 begin和end的方法begin和end就是for循环迭代的范围。 注意以下代码就有问题因为for的范围不确定 void TestFor(int array[]) {for(auto e : array)cout e endl; } 九.空值nullptr NULL可能被定义为字面常量0或者被定义为无类型指针(void*)的常量。 十.类与对象 1.class与struct C语言结构体中只能定义变量在C中结构体内不仅可以定义变量也可以定义函数。 比如 之前在数据结构初阶中用C语言方式实现的栈结构体中只能定义变量现在以C方式实现 会发现struct中也可以定义函数。 class默认私有struct默认公有 2.类的定义 class className{类体由成员函数和成员变量组成};   一定要注意后面的分号 class为定义类的关键字ClassName为类的名字{}中为类的主体注意类定义结束时后面分 号不能省略。 类体中内容称为类的成员类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。 类的两种定义方式 1. 声明和定义全部放在类体中 需注意成员函数如果在类中定义编译器可能会将其当成内 联函数处理。 2. 类声明放在.h文件中,成员函数定义放在.cpp文件中 注意成员函数名前需要加类名:: ①模版的情况下 3.成员变量命名规则的建议 // 我们看看这个函数是不是很僵硬class Date{public:void Init(int year){// 这里的year到底是成员变量还是函数形参year year;}private:int year; };所以一般都建议这样 class Date{public:void Init(int year){_year year;}private:int _year; };3.类的访问限定符及封装 1 访问限定符 C实现封装的方式用类将对象的属性与方法结合在一块让对象更加完善通过访问权限选 择性的将其接口提供给外部的用户使用。 2.访问限定符说明 1. public修饰的成员在类外可以直接被访问 2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的) 3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止 4. 如果后面没有访问限定符作用域就到 } 即类结束。 5. class的默认访问权限为privatestruct为public(因为struct要兼容C) 注意访问限定符只在编译时有用当数据映射到内存后没有任何访问限定符上的区别 访问限定符在继承中 在继承中pricvate和protected是有很大区别的,private是直接不可见,protected也一样不可以访问但可以继承,private是都不行,基本用不到常用的只有 3.C中struct和class的区别是什么 解答C需要兼容C语言所以C中struct可以当成结构体使用。另外C中struct还可以用来 定义类。和class定义类是一样的区别是struct定义的类默认访问权限是publicclass定义的类 默认访问权限是private。注意在继承和模板参数列表位置struct和class也有区别继承中struct默认是公有而private是私有继承 4.封装 面向对象的三大特性封装、继承、多态。 封装将数据和操作数据的方法进行有机结合隐藏对象的属性和实现细节仅对外公开接口来 和对象进行交互。 封装本质上是一种管理让用户更方便使用类。 4.类的作用域 类定义了一个新的作用域类的所有成员都在类的作用域中。在类体外定义成员时需要使用 :: 作用域操作符指明成员属于哪个类域。 class Person{public:void PrintPersonInfo();private:char _name[20];char _gender[3];int  _age; };这里需要指定PrintPersonInfo是属于Person这个类域void Person::PrintPersonInfo() {cout _name _gender _age endl; 5.类的实例化 用类类型创建对象的过程称为类的实例化 1. 类是对对象进行描述的是一个模型一样的东西限定了类有哪些成员定义出一个类并没有分配实际的内存空间来存储它比如入学时填写的学生信息表表格就可以看成是一个 类来描述具体学生信息。 2. 一个类可以实例化出多个对象实例化出的对象 占用实际的物理空间存储类成员变量 Person类是没有空间的只有Person类实例化出的对象才有具体的年龄代码例子 int main() {Person._age 100;  编译失败error C2059: 语法错误:“.”return 0; } 3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子类就像是设计图只设 计出需要什么东西但是并没有实体的建筑存在同样类也只是一个设计实例化出的对象才能实际存储数据占用物理空间 6.类对象模型  1 如何计算类对象的大小结构体内存对齐 结论一个类的大小实际就是该类中”成员变量”之和当然要注意内存对齐注意空类的大小空类比较特殊编译器给了空类一个字节来唯一标识这个类的对象。 7.this指针 C中通过引入this指针解决该问题即C编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数让该指针指向当前对象(函数运行时调用该函数的对象)在函数体中所有“成员变量”的操作都是通过该指针去访问。只不过所有的操作对用户是透明的即用户不需要来传递编 译器自动完成。 1. this指针的类型类类型* const即成员函数中不能给this指针赋值。 2. 只能在“成员函数”的内部使用 3. this指针本质上是“成员函数”的形参当对象调用成员函数时将对象地址作为实参传递给 this形参。所以对象中不存储this指针。 4. this指针是“成员函数”第一个隐含的指针形参一般情况由编译器通过ecx寄存器自动传 递不需要用户传递 8.类的6个默认成员函数  如果一个类中什么成员都没有简称为空类。 空类中真的什么都没有吗并不是任何类在什么都不写时编译器会自动生成以下6个默认成员函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数。 class Date {};1.构造函数 构造函数是一个特殊的成员函数名字与类名相同,创建类类型对象时由编译器自动调用以保证 每个数据成员都有 一个合适的初始值并且在对象整个生命周期内只调用一次。 构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任 务并不是开空间创建对象而是初始化对象。 其特征如下 1. 函数名与类名相同。 2. 无返回值。 3. 对象实例化时编译器自动调用对应的构造函数。 4. 构造函数可以重载。 // 带参构造函数 Date(int year, int month, int day){_year year;_month month;_day day;}// 无参构造函数 Date(){}//调用 Date d1; // 调用无参构造函数 Date d2(2015, 1, 1); // 调用带参的构造函数 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦 用户显式定义编译器将不再生成。 //关于编译器生成的默认成员函数很多童鞋会有疑惑不实现构造函数的情况下编译器会 生成默认的构造函数。但是看起来默认构造函数又没什么用d对象调用了编译器生成的默 认构造函数但是d对象_year/_month/_day依旧是随机值。也就说在这里编译器生成的 默认构造函数并没有什么用 内置类型和自定义类型在构造中 解答C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型如int/char...自定义类型就是我们使用class/struct/union等自己定义的类型看看 下面的程序就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。 lass Time{public:Time(){cout Time() endl;_hour 0;_minute 0;_second 0;}private:int _hour;int _minute;int _second; };class Date{private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t; };int main() {Date d;return 0; }注意内置类型成员变量在 类中声明时可以给默认值。 无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。 注意无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为是默认构造函数。 小知识点: 初始化的两种方式一个构造函数体赋值和初始化列表  初始化列表不能检查扩容是否成功要在{ }z中 2.析构函数 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。 析构函数是特殊的成员函数其特征如下 1. 析构函数名是在类名前加上字符 ~。 2. 无参数无返回值类型。 3. 一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意析构 函数不能重载 4. 对象生命周期结束时C编译系统系统自动调用析构函数。 内置类型和自定义类型在析构中 关于编译器自动生成的析构函数是否会完成一些事情呢下面的程序我们会看到编译器生成的默认析构函数对自定类型成员调用它的析构函数。 class Time{public:~Time(){cout ~Time() endl;}private:int _hour;int _minute;int _second; };class Date{private:// 基本类型(内置类型)int _year 1970;int _month 1;int _day 1;// 自定义类型Time _t; };int main() {Date d;return 0; }程序运行结束后输出~Time() 在main方法中根本没有直接创建Time类的对象为什么最后会调用Time类的析构函数 因为main方法中创建了Date对象d而d中包含4个成员变量其中_year, _month, _day三个是内置类型成员销毁时不需要资源清理最后系统直接将其内存回收即可 而_t是Time类对象所以在d销毁时要将其内部包含的Time类的_t对象销毁所以要调用Time类的析构函数。 但是main函数中不能直接调用Time类的析构函数实际要释放的是Date类对象所以编译器会调用Date类的析构函数而Date没有显式提供则编译器会给Date类生成一个默认的析构函数目的是在其内部调用Time类的析构函数即当Date对象销毁时要保证其内部每个自定义对象都可以正确销毁main函数中并没有直接调用Time类析构函数而是显式调用编译器为Date类生成的默认析构函数 注意创建哪个类的对象则调用该类的析构函数销毁那个类的对象则调用该类的析构函数 如果类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数比如 Date类有资源申请时一定要写否则会造成资源泄漏比如Stack类。 小知识点析构顺序 设已经有A,B,C,D4个类的定义程序中A,B,C,D析构函数调用顺序为 C c; int main() { A a; B b; static D d; return 0 } 分析:1、类的析构函数调用一般按照构造函数调用的相反顺序进行调用但是要注意static对象的存在 因为static改变了对象的生存作用域需要等待程序结束时才会析构释放对象 a,b是局部对象而且遵循先创建的后销毁的原则 2、全局对象先于局部对象进行构造 3、局部对象按照出现的顺序进行构造无论是否为static 4、所以构造的顺序为 c a b d 5、析构的顺序按照构造的相反顺序析构只需注意static改变对象的生存作用域之后会放在局部 对象之后进行析构 6、因此析构顺序为B A D C 析构顺序和次数 1设已经有A,B,C,D4个类的定义程序中A,B,C,D析构函数调用顺序为 C c; void main() { A*panew A(); B b; static D d; delete pa; }分析:首先手动释放pa 所以会先调用A的析构函数其次会跟定义相反的顺序释放局部对象这里只有b就释放b再释放静态局部对象d再释放全局对象c 2以下代码中A 的构造函数和析构函数分别执行了几次 (10,10 ) A*panew A[10]; delete []pa; A.申请数组空间构造函数调用的次数就是数组的大小 B.正确 C.申请数组空间构造函数调用的次数就是数组的大小 D.如果释放数组空间delete使用了[]则会对应的调用数组大小次数的析构函数 3.拷贝构造函数 那在创建对象时可否创建一个与已存在对象一某一样的新对象呢 拷贝构造函数只有单个形参该形参是对本类类型对象的引用(一般常用const修饰)在用已存 在的类类型对象创建新对象时由编译器自动调用。 拷贝构造函数也是特殊的成员函数其特征如下 1. 拷贝构造函数是构造函数的一个重载形式。 2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错 因为会引发无穷递归调用。 Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}// Date(const Date d)   // 正确写法Date(const Date d)   // 错误写法编译报错会引发无穷递归{_year d._year;_month d._month;_day d._day; } 内置类型和自定义类型在拷贝构造 若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。   注意在编译器生成的默认拷贝构造函数中内置类型是按照字节方式直接拷贝的而自定义类型是调用其拷贝构造函数完成拷贝的。 注意类中如果没有涉及资源申请时拷贝构造函数是否写都可以一旦涉及到资源申请时则拷贝构造函数是一定要写的否则就是浅拷贝。 拷贝构造函数典型调用场景 使用已存在对象创建新对象函数参数类型为类类型对象 函数返回值类型为类类型对象. 为了提高程序效率一般对象传参时尽量使用引用类型返回时根据实际场景能用引用 尽量使用引用。 9.赋值运算符重载 运算符重载 返回*this Date operator(const Date d){if(this ! d){_year d._year;_month d._month;_day d._day;}return *this;}C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其 返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型operator操作符(参数列表) 注意 不能通过连接其他符号来创建新的操作符比如operator 重载操作符必须有一个类类型参数 用于内置类型的运算符其含义不能改变例如内置的整型不能改变其含义 作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐 藏的this .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。 全局的operator 这里会发现运算符重载成全局的就需要成员变量是公有的那么问题来了封装性如何保证 这里其实可以用我们后面学习的友元解决或者干脆重载成成员函数。 bool operator(const Date d1, const Date d2) {return d1._year d2._year d1._month d2._month d1._day d2._day; }类内的operator //bool operator(Date* this, const Date d2)// 这里需要注意的是左操作数是this指向调用函数的对象bool operator(const Date d2){return _year d2._year; _month d2._month _day d2._day;赋值运算符重载 赋值运算符重载格式参数类型const T传递引用可以提高传参效率 返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值 检测是否自己给自己赋值 返回*this 要复合连续赋值的含义 注意:赋值运算符只能重载成类的成员函数不能重载成全局函数,赋值运算符重载成全局函数注意重载成全局函数时没有this指针了需要给两个参数,“operator ”必须是非静态成员 内置类型和自定义类型在赋值运算符重载 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。注 意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。 小知识点: 两个已经存在的对象赋值才是赋值  拷贝构造是一个存在一个不存在 日期类的实现(已经弄完了)  10.初始化列表 虽然上述构造函数调用之后对象中已经有了一个初始值但是不能将其称为对对象中成员变量的初始化 构造函数体中的语句只能将其称为赋初值而不能称作初始化。因为初始化只能初始化一次而构造函数体 内可以多次赋值。 初始化列表以一个冒号开始接着是一个以逗号分隔的数据成员列表每个成员变量后面跟一个放在括 号中的初始值或表达式。 注意】 1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次) 2. 类中包含以下成员必须放在初始化列表位置进行初始化 引用成员变量 const成员变量 自定义类型成员(且该类没有默认构造函数时) class A{public:A(int a):_a(a){}private:int _a; };class B{public:B(int a, int ref):_aobj(a),_ref(ref),_n(10){}private:A _aobj; // 没有默认构造函数int _ref; // 引用const int _n; // const }; 尽量使用初始化列表初始化因为不管你是否使用初始化列表对于自定义类型成员变量一定会先使 用初始化列表初始化。 成员变量在类中声明次序就是其在初始化列表中的初始化顺序与其在初始化列表中的先后次序无关 小知识点: 初始化的两种方式一个构造函数体赋值和初始化列表  初始化列表不能检查扩容是否成功要在{ }z中 11.static成员explicit关键字 声明为static的类成员称为类的静态成员用static修饰的成员变量称之为静态成员变量用static修饰的成员函数称之为静态成员函数。静态成员变量一定要在类外进行初始化。 1. 静态成员为所有类对象所共享不属于某个具体的对象存放在静态区 2. 静态成员变量必须在类外定义定义时不添加static关键字类中只是声明 3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏的this指针不能访问任何非静态成员 5. 静态成员也是类的成员受public、protected、private 访问限定符的限制 小知识点: 概念 声明为static的类成员称为类的静态成员用static修饰的成员变量称之为静态成员变量用static修饰的成员函数称之为静态成员函数。静态成员变量一定要在类外进行初始化  特性 1. 静态成员为所有类对象所共享不属于某个具体的对象存放在静态区 2. 静态成员变量必须在类外定义定义时不添加static关键字类中只是声明 3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问 4. 静态成员函数没有隐藏的this指针不能访问任何非静态成员 5. 静态成员也是类的成员受public、protected、private 访问限定符的限制 知识点 局部的静态成员不会在main之前初始化全局的在mian之前就会调用默认构造 自定义传参要调用拷贝构造 多次调用静态也只会创建一次 private中有成员变量属于每个类对象储存在对象里 静态成员变量属于类属于类的每个对象存储在静态区生命周期是全局的 静态成员变量不能在private中直接赋值 静态成员变量的初始化必须在类外定义可已突破私有 静态成员变量一般配套静态成员函数 非静态可以调用静态 静态成员函数不能访问非静态成员变量因为无this指针 全局变量的缺点任何地方都可以进行修改 例题12345...n不能用forwhile求123...n_牛客题霸_牛客网 (nowcoder.com) 全局对象和静态对象出了作用于还在静态区 任何类型的指针都是内置类型 赋值运算符不能重载成全局的  默认成员函数都不能写到全局 全局的静态成员会在进入main之前就初始化  局部的相反  静态成员调用多次只创建一次和内联函数的作用类似  静态成员变量存储在静态区生命周期是全局的    静态成员初始化必须在类外定义时可以突破私有   静态成员函数不能访问非静态成员变量无this指针  12this指针 this指针不能在形参或者实参的位置显示 传值返回 返回的是他的拷贝所以要调用一次拷贝构造 传引用返回返回的是他的别名 this指针的特性 1. this指针的类型类类型* const即成员函数中不能给this指针赋值。 2. 只能在“成员函数”的内部使用 3. this指针本质上是“成员函数”的形参当对象调用成员函数时将对象地址作为实参传递给 this形参。所以对象中不存储this指针。 4. this指针是“成员函数”第一个隐含的指针形参一般情况由编译器通过ecx寄存器自动传 递不需要用户传递 this的定义 const指向thisthis不能改指向的可以改const Dat*this/Dat const*this指向的不可以改 this在哪里 this是形参所以this指针跟普通函数一样存在函数调用的栈帧里面 空间没有消失 C中通过引入this指针解决该问题即C编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数让该指针指向当前对象(函数运行时调用该函数的对象)在函数体中所有“成员变量” 的操作都是通过该指针去访问。只不过所有的操作对用户是透明的即用户不需要来传递编 译器自动完成。 就是调用这个函数的时候 得保证当前调用函数的这个对象是存在的  这里肯定是没销毁的  因为返回的是当前对象本身 传值返回 返回的是他的拷贝所以要调用一次拷贝构造 传引用返回返回的是他的别名 a.静态成员函数没有this指针只有非静态成员函数才有且为隐藏指针 B.非静态成员函数的第一个参数就是隐藏的this指针 C.this指针在非静态的成员函数里面对象不存在故错误 D.单纯的对this赋空是不可以的不过可以强转直接赋空不过一般不进行这样的操作 13.友元函数和友元类(Date里有) 问题现在尝试去重载operator然后发现没办法将operator重载成成员函数。因为cout的输出流对 象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用 中cout需要是第一个形参对象才能正常使用。所以要将operator重载成全局函数。但又会导致类外没办 法访问成员此时就需要友元来解决。operator同理 元函数可以直接访问类的私有成员它是定义在类外部的普通函数不属于任何类但需要在类的内部声 明声明时需要加friend关键字。 class Date{friend ostream operator(ostream _cout, const Date d);friend istream operator(istream _cin, Date d);public:Date(int year 1900, int month 1, int day 1): _year(year), _month(month), _day(day){}private: int _year;int _month;int _day; };ostream operator(ostream _cout, const Date d) {_cout d._year - d._month - d._day;return _cout; }istream operator(istream _cin, Date d) {_cin d._year;_cin d._month;_cin d._day;return _cin; }int main() {Date d;cin d;cout d endl;return 0; } 说明: 友元函数可访问类的私有和保护成员但不是类的成员函数 友元函数不能用const修饰 友元函数可以在类定义的任何地方声明不受类访问限定符限制 一个函数可以是多个类的友元函数 友元函数的调用与普通函数的调用原理相同 友元类 友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员。 友元关系是单向的不具有交换性 比如上述Time类和Date类在Time类中声明Date类为其友元类那么可以在Date类中直接访问Time类的私有成员变量但想在Time类中访问Date类中私有的成员变量则不行。 友元关系不能传递 如果B是A的友元C是B的友元则不能说明C时A的友元。 友元关系不能继承 一个类的友元函数能够访问类的( ) A.私有成员 B.保护成员 C.公有成员 D.所有成员 A.可以访问这也把一个函数声明为友元的目的 B.可以访问 C.可以访问 D.友元函数对一个类里面的所有成员全部通吃正确 A.友元函数不是类的成员函数就相当于你的朋友再亲密也不是你的家人既然不是类成员函数那和普通成员函数调用一样不需要通过对象调用 B.友元的目的就是为了访问类的私有数据成员函数可以直接访问类的私有数据 C.类的成员函数属于类调用时其内部数据会通过this指针来调用 D.友元函数不具备this指针更谈不上通过this调用故错误 全局函数不具备this指针 B.static函数不具备this指针 C.友元函数不具备this指针 D.正确普通成员方法具有隐藏的this指针 十一.内存管理 函数参数使用的空间是在中申请的malloc或new是在中申请空间的 答 A.参数在栈空间存放malloc或new申请的空间为堆区 B.正确 C.参数在栈空间存放malloc或new申请的空间为堆区 D.参数在栈空间存放malloc或new申请的空间为堆区 【说明】 1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等栈是向下增长的。 2. 内存映射段是高效的I/O映射方式用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存做进程间通信。Linux课程如果没学到这块现在只需要了解一下 3. 堆用于程序运行时动态内存分配堆是可以上增长的。 4. 数据段--存储全局数据和静态数据。 5. 代码段--可执行的代码/只读常量。 new int[3]{1,2,3};开空间加初始化 new是操作符 ”abcd”是常量字符串不可修改在常量区 C语言中动态内存管理方式malloc/calloc/realloc/free void Test () {int* p1 (int*) malloc(sizeof(int));free(p1);// 1.malloc/calloc/realloc的区别是什么int* p2 (int*)calloc(4, sizeof (int));int* p3 (int*)realloc(p2, sizeof(int)*10);// 这里需要free(p2)吗free(p3 ); }C内存管理方式 C语言内存管理方式在C中可以继续使用但有些地方就无能为力而且使用起来比较麻烦因此C又提 出了自己的内存管理方式通过new和delete操作符进行动态内存管理。 new/delete操作内置类型 void Test() {// 动态申请一个int类型的空间int* ptr4 new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 new int(10);// 动态申请10个int类型的空间int* ptr6 new int[10];delete ptr4;delete ptr5;delete[] ptr6; }new和delete操作自定义类型 class A{public:A(int a 0): _a(a){cout A(): this endl;}~A(){cout ~A(): this endl;}private:int _a; };int main() {// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构 造函数和析构函数A* p1 (A*)malloc(sizeof(A));A* p2 new A(1);free(p1);delete p2;// 内置类型是几乎是一样的int* p3 (int*)malloc(sizeof(int)); // Cint* p4 new int;free(p3);delete p4;A* p5 (A*)malloc(sizeof(A)*10);A* p6 new A[10];free(p5);delete[] p6;return 0; } 注意在申请自定义类型的空间时new会调用构造函数delete会调用析构函数而malloc与free不会。 operator new与operator delete函数 new和delete是用户进行动态内存申请和释放的操作符operator new 和operator delete是系统提供的 全局函数new在底层调用operator new全局函数来申请空间delete在底层通过operator delete全局 函数来释放空间。 /* operator new该函数实际通过malloc来申请空间当malloc申请空间成功时直接返回申请空间失败 尝试执行空 间不足应对措施如果改应对措施用户设置了则继续申请否则抛异常。*/void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) {// try to allocate size bytesvoid *p;while ((p malloc(size)) 0)if (_callnewh(size) 0){// report no memory// 如果申请内存失败了这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}return (p); }/* operator delete: 该函数最终是通过free来释放空间的*/void operator delete(void *pUserData) {_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0)); if (pUserData NULL)return;_mlock(_HEAP_LOCK); /* block other threads */__TRY/* get a pointer to memory block header */pHead pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-nBlockUse));_free_dbg( pUserData, pHead-nBlockUse );__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn; }/* free的实现*/#define free(p) _free_dbg(p, _NORMAL_BLOCK)通过上述两个全局函数的实现知道operator new 实际也是通过malloc来申请空间如果malloc申请空间 成功就直接返回否则执行用户提供的空间不足应对措施如果用户提供该措施就继续申请否则就抛异 常。operator delete 最终是通过free来释放空间的。 new和delete的实现原理(new后要手动释放空间) 内置类型 如果申请的是内置类型的空new和mallocdelete和free基本类似不同的地方是new/delete申请和释放的是单个元素的空间new[]和delete[]申请的是连续空间而且new在申请空间失败时会抛异常malloc会返回NULL。 自定义类型 new的原理 1. 调用operator new函数申请空间 2. 在申请的空间上执行构造函数完成对象的构造 delete的原理 1. 在空间上执行析构函数完成对象中资源的清理工作 2. 调用operator delete函数释放对象的空间 new T[N]的原理 1. 调用operator new[]函数在operator new[]中实际调用operator new函数完成N个对象空间的申 请 2. 在申请的空间上执行N次构造函数 delete[]的原理 1. 在释放的对象空间上执行N次析构函数完成N个对象中资源的清理 2. 调用operator delete[]释放空间实际在operator delete[]中调用operator delete来释放空间 定位new表达式(placement-new) 了解 定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。 使用格式 new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针initializer-list是类型的初始化列表 使用场景 定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化所以如果是自定义 类型的对象需要使用new的定义表达式进行显示调构造函数进行初始化。 class A{public:A(int a 0): _a(a){cout A(): this endl;}~A(){cout ~A(): this endl;}private:int _a; };// 定位new/replacement newint main() {// p1现在指向的只不过是与A对象相同大小的一段空间还不能算是一个对象因为构造函数没有执行A* p1 (A*)malloc(sizeof(A));new(p1)A; // 注意如果A类的构造函数有参数时此处需要传参p1-~A();free(p1);A* p2 (A*)operator new(sizeof(A));new(p2)A(10);p2-~A();operator delete(p2);return 0; } malloc/free和new/delete的区别 malloc/free和new/delete的共同点是都是从堆上申请空间并且需要用户手动释放。不同的地方是 1. malloc和free是函数new和delete是操作符 2. malloc申请的空间不会初始化new可以初始化 3. malloc申请空间时需要手动计算空间大小并传递new只需在其后跟上空间的类型即可 如果是多个 对象[]中指定对象个数即可 4. malloc的返回值为void*, 在使用时必须强转new不需要因为new后跟的是空间的类型 5. malloc申请空间失败时返回的是NULL因此使用时必须判空new不需要但是new需要捕获异常 6. 申请自定义类型对象时malloc/free只会开辟空间不会调用构造函数与析构函数而new在申请空间 后会调用构造函数完成对象的初始化delete在释放空间前会调用析构函数完成空间中资源的清理 内存泄漏 什么是内存泄漏内存泄漏的危害 什么是内存泄漏内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不 是指内存在物理上的消失而是应用程序分配某段内存后因为设计错误失去了对该段内存的控制因而 造成了内存的浪费。 内存泄漏的危害长期运行的程序出现内存泄漏影响很大如操作系统、后台服务等等出现内存泄漏会 导致响应越来越慢最终卡死。 void MemoryLeaks(){// 1.内存申请了忘记释放int* p1 (int*)malloc(sizeof(int));int* p2 new int;// 2.异常安全问题int* p3 new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行p3没被释放.delete[] p3;}内存泄漏分类了解 C/C程序中一般我们关心两种方面的内存泄漏 堆内存泄漏(Heap leak)、 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存 用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放那 么以后这部分空间将无法再被使用就会产生Heap Leak。 系统资源泄漏 指程序使用系统分配的资源比方套接字、文件描述符、管道等没有使用对应的函数释放掉导致系统 资源的浪费严重可导致系统效能减少系统执行不稳定。 如何避免内存泄漏 1. 工程前期良好的设计规范养成良好的编码规范申请的内存空间记着匹配的去释放。ps这个理想状 态。但是如果碰上异常时就算注意释放了还是可能会出问题。需要下一条智能指针来管理才有保 证。 2. 采用RAII思想或者智能指针来管理资源。 3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。 4. 出问题了使用内存泄漏工具检测。ps不过很多工具都不够靠谱或者收费昂贵。 总结一下: 内存泄漏非常常见解决方案分为两种1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。 小知识点new和delete【】匿名对象和重复释放 malloc realloc calloc free new delete new[] delete[] 要匹配使用 匿名对象创建完立刻销毁 例题 1ClassA *pclassanew ClassA[5];//调用5次构造函数new[]的连续的 delete pclassa;这里相当于只是将第一个对象释放 c语言中类ClassA的构造函数和析构函数的执行次数分别为( )会崩溃 解答 A.申请对象数组会调用构造函数5次delete由于没有使用[]此时只会调用一次析构函数但往往会引发程序崩溃 B.构造函数会调用5次 C.析构函数此时只会调用1次要想完整释放数组空间需要使用[] 注意如果一个类定义了析构函数再使用new[]申请对象时编译器会多申请四个字节用来存放对象个数 2使用 char* p new char[100]申请一段内存然后使用delete p释放有什么问题( ) 答A.对于内置类型此时delete就相当于free因此不会造成内存泄漏 B.正确 C.编译不会报错建议针对数组释放使用delete[],如果是自定义类型不使用方括号就会运行时错误 D.对于内置类型程序不会崩溃但不建议这样使用 3class A{ int i; }; class B{ A *p; public: B(){pnew A;} ~B(){delete p;} }; void sayHello(B b){ } i nt main() { B b; sayHello(b); } 答 会重复释放 因为参数b是浅拷贝main函数中的b所以两个对象销毁的时候都是执行delete p 重复释放会导致程序崩溃   A.new会申请空间同时调用构造函数初始化对象malloc只做一件事就是申请空间 B.new/delete与malloc/free最大区别就在于是否会调用构造函数与析构函数 C.需要头文件malloc.h,只是平时这个头文件已经被其他头文件所包含了用的时候很少单独引入故错误 D.new是操作符malloc是函数 十二.函数模版和类模版 函数模板 函数模板概念 函数模板代表了一个函数家族该函数模板与类型无关在使用时被参数化根据实参类型产生函数的特定 类型版本 函数模板格式 .1 函数模板格式 templatetypename T1, typename T2,......,typename Tn 返回值类型 函数名(参数列表){} templatetypename Tvoid Swap( T left, T right) { T temp left; left right;right temp; } 注意typename是用来定义模板参数关键字也可以使用class(切记不能使用struct代替class) 在编译器编译阶段对于模板函数的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如当用double类型使用函数模板时编译器通过对实参类型的推演将T确定为double类型然后产生一份专门处理double类型的代码对于字符类型也是如此。 函数模板的实例化 用不同类型的参数使用函数模板时称为函数模板的实例化。模板参数实例化分为隐式实例化和显式实例化。 1. 隐式实例化让编译器根据实参推演模板参数的实际类型(用int强转) templateclass TT Add(const T left, const T right){return left right;}int main(){int a1 10, a2 20;double d1 10.0, d2 20.0;Add(a1, a2);Add(d1, d2);该语句不能通过编译因为在编译期间当编译器看到该实例化时需要推演其实参类型 通过实参a1将T推演为int通过实参d1将T推演为double类型但模板参数列表中只有一个T 编译器无法确定此处到底该将T确定为int 或者 double类型而报错 注意在模板中编译器一般不会进行类型转换操作因为一旦转化出问题编译器就需要背黑锅 Add(a1, d1); // 此时有两种处理方式1. 用户自己来强制转化 2. 使用显式实例化Add(a1, (int)d1);return 0; } 显式实例化在函数名后的中指定模板参数的实际类型 int main(void){int a 10;double b 20.0;// 显式实例化Addint(a, b);return 0;} 如果类型不匹配编译器会尝试进行隐式类型转换如果无法转换成功编译器将会报错。 重要例子 错误示例 templateclass T T add(Tleft,Tright) {return leftright; } int main() {int a1;double b2.0;add(a,(int)b); } 这里面的b会传不过去因为强制类型转换会产生临时变量有常性不可修改所以要在接收b处加一个const 注意由于参数类型不一样模板不支持类型转换推导参数会产生二义性编译错误 类模版 类模板的定义格式  templateclass T1, class T2, ..., class Tn class 类模板名{// 类内成员定义}; 动态顺序表 注意Vector不是具体的类是编译器根据被实例化的类型生成具体类的模具 templateclass Tclass Vector{ public :Vector(size_t capacity 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}// 使用析构函数演示在类中声明在类外定义。~Vector();void PushBack(const T data)void PopBack()// ...size_t Size() {return _size;}T operator[](size_t pos) {assert(pos _size);return _pData[pos];}private:T* _pData;size_t _size;size_t _capacity; };注意类模板中函数放在类外进行定义时需要加模板参数列表template class TVectorT::~Vector() {if(_pData)delete[] _pData;_size _capacity 0; }类模板的实例化 类模板实例化与函数模板实例化不同类模板实例化需要在类模板名字后跟然后将实例化的类型放在中即可类模板名字不是真正的类而实例化的结果才是真正的类。 Vector类名Vectorint才是类型 Vectorint s1; Vectordouble s2; 十三.string vector list stack queue priority_queue 反向迭代器 模拟实现中几乎都有这里补充一下 函数模板特化 函数模板的特化步骤 1. 必须要先有一个基础的函数模板 2. 关键字template后面接一对空的尖括号 3. 函数名后跟一对尖括号尖括号中指定需要特化的类型 4. 函数形参表: 必须要和模板函数的基础参数类型完全相同如果不同编译器可能会报一些奇怪的错误。 // 函数模板 -- 参数匹配templateclass Tbool Less(T left, T right) {return left right; }// 对Less函数模板进行特化templatebool LessDate*(Date* left, Date* right) {return *left *right; }int main() {cout Less(1, 2) endl;Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout Less(d1, d2) endl;Date* p1 d1;Date* p2 d2;cout Less(p1, p2) endl; // 调用特化之后的版本而不走模板生成了return 0; }注意一般情况下如果函数模板遇到不能处理或者处理有误的类型为了实现简单通常都是将该函数直接给出。 bool Less(Date* left, Date* right) {return *left *right; }类模板特化 全特化 templateclass T1, class T2 class Data{public:Data() {coutDataT1, T2 endl;}private:T1 _d1;T2 _d2; };template class Dataint, char{public:Data() {coutDataint, char endl;}private:int _d1;char _d2; };void TestVector() {Dataint, int d1;Dataint, char d2; } 偏特化 templateclass T1, class T2 class Data{public:Data() {coutDataT1, T2 endl;}private:T1 _d1;T2 _d2; };偏特化有以下两种表现方式 部分特化 将模板参数类表中的一部分参数特化。 两个参数偏特化为指针类型 template typename T1, typename T2 class Data T1*, T2* { public:Data() {coutDataT1*, T2* endl;}两个参数偏特化为引用类型 template typename T1, typename T2 class Data T1, T2模板的分离编译 // a.htemplateclass TT Add(const T left, const T right); // a.cpp templateclass TT Add(const T left, const T right) {return left right; }// main.cpp#includea.hint main() {Add(1, 2);Add(1.0, 2.0);return 0; }解决方法 1. 将声明和定义放到一个文件 xxx.hpp 里面或者xxx.h其实也是可以的。推荐使用这种。 2. 模板定义的位置显式实例化。这种方法不实用不推荐使用。 模板总结 优点 1. 模板复用了代码节省资源更快的迭代开发C的标准模板库(STL)因此而产生 2. 增强了代码的灵活性 【缺陷】 1. 模板会导致代码膨胀问题也会导致编译时间变长 2. 出现模板编译错误时错误信息非常凌乱不易定位错误 知识点总结(易遗漏): 临时对象具有常性  函数返回的值具有常性 隐式类型转换也有常性因为转换的过程需要创建临时变量   全特化和偏特化和仿函数在(优先级队列的模拟实现中) 优先级队列priority_queue底层采用vector容器作为底层数据结构 优先级队列默认情况为大堆 priority_queueint, vectorint, greaterint c; //c指定了比较规则是小堆 vector、deque底层都是用了连续空间所以虽然iter迭代器了但是erase(tempit)以后 底层是连续空间删除会挪动数据最终导致iter意义变了已失效了。 而list不是连续空间删除以后tempIt虽然失效了但是不影响iter。 list不支持随机访问不支持[ ]空间不连续 list,erase(it)删除节点后只有指向当前节点的迭代器失效了其前后的迭代器仍然有效因为底层为不连续空间只有被删除的节点才会失效 list的insert后不影响什么。而vector的insert会影响扩容所以vector用完insert后就不能再使用其返回的地址了可能已经失效了 如果需要高效的随机存取还要大量的首尾的插入删除则建议使用deque,deque底层总体为不连续空间 vector底层是以当前类型的指针作为迭代器对于指针而言能够进行操作的方法都支持如,,*而运算符并没有重载 at() 和 operator[] 都是根据下标获取任意位置元素的在debug模式下两者都会去做边界检查。 当发生越界行为时at 是抛异常operator[] 内部的assert会触发 vector容量满时一般会以容量的2倍扩充容量这是为了减少扩容的次数减少内存碎片 vectorint v(ar, arn); coutv.size():v.capacity()endl; //大小为数组元素个数因此size10 capacity10 v.reserve(100); //预留空间100 v.resize(20);  //调整元素为20个此时元素的size会改变由于个数小于容量因此容量不会变小v.reserve(50);//期望预留空间为50可是现在的空间已经有100个所以空间不会减小v.resize(5); //元素个数调整为5 A.如果想大量随机读取数据操作vector是首选的容器 B.如果想大量的插入和删除数据list效率较高是首选 C.由于vector底层是连续空间其迭代器就是相应类型的指针所以支持对应的操作 D.list迭代器不支持[]运算符 A.vector在尾部插入数据不需要移动数据list为双向循环链表也很容易找到尾部因此两者在尾部插入数据效率相同 B.vector头部插入效率极其低需要移动大量数据 C.vector由于在头部插入数据效率很低所以没有提供push_front方法 D.list不支持随机访问 A.如果想大量随机读取数据操作vector是首选的容器 B.如果想大量的插入和删除数据list效率较高是首选 C.由于vector底层是连续空间其迭代器就是相应类型的指针所以支持对应的操作 D.list迭代器不支持[]运算符 A.vector的插入操作如果导致底层空间重新开辟则迭代器就会失效。如果空间足够不扩容时迭代器不一定失效比如push_back尾插元素插入到空间末尾在不扩容时不会对迭代器产生影响 C.vector删除当前元素肯定失效后面元素会牵扯到移动数据因此删除元素后面的迭代器也会失效 D. vector的删除操作不光会导致指向被删除元素的迭代器失效删除元素后面的迭代器也会失效 vectorintv(10,1) 算法sort(v.begin()v.end(),greaterint())优先级队列模拟实现中而模版中是类型是templateclass T,class Ref,class greater  不用带括号不过优先级队列默认是less,大堆 it mylist.erase(it);,erase后需要接受一下返回值要不然当前的it就失效了 c_str 例题 int main(int argc, char *argv[]) { string ahello world; string ba; if (a.c_str()b.c_str()) { couttrueendl; } else coutfalseendl; string cb; c; if (a.c_str()b.c_str()) { couttrueendl; } else coutfalseendl; a; if (a.c_str()b.c_str()) { couttrueendl; } else coutfalseendl; return 0; } 答a 和 b的值虽然相同但是a.c_str()b.c_str()比较的是存储字符串位置的地址a和b是两个不同的对象内部数据存储的位置也不相同因此不相等后面c,a与b对象都没有任何的影响所以都不相等 仿函数 A.仿函数是模板函数可以根据不同的类型代表不同的状态 B.仿函数是模板函数可以有不同类型 C.仿函数是模板函数其速度比一般函数要慢,故错误 D.仿函数在一定程度上使代码更通用本质上简化了代码
http://www.w-s-a.com/news/935175/

相关文章:

  • 福州网站建设H5广告公司简介简短
  • 网站404页面的作用app开发郑州
  • 亚马逊中国网站建设目标网站建设的策划
  • 林州网站建设服务徐州网站建设
  • 如何检测网站死链景德镇网站建设哪家好
  • 旅游网站开发目标天津专业做网站公司
  • 名者观看网站快手小程序
  • 网络架构扁平化windows优化大师好不好
  • 安康养老院收费价格表兰州seo整站优化服务商
  • 网站开发技术方案模板无锡网站建设推荐
  • 自助建站系统注册三维家3d设计软件免费
  • 做seo网站标题重要吗郑州众诚建设监理有限公司网站
  • 建设网站南沙区百度关键词推广怎么做
  • 网站建设公司做销售前景好不好石家庄外贸网站制作
  • windows2008做网站网站首页打开速度
  • 做外贸要做什么网站服装设计图
  • 中山市路桥建设有限公司网站网站开发角色分配权限
  • 加强档案网站建设网站搭建好了不用会不会被攻击
  • 维护网站信息网络建设服务
  • 网站建设策划书模板下载用自己电脑配置服务器做网站
  • 360免费建站空间淘宝数据网站开发
  • 做分销的网站本地dede网站怎么上线
  • 中学网站模板北京管理咨询公司
  • 网站开发用哪个软件方便二级网站建设 管理思路
  • 个人怎么创建网站中国建设银行网站口
  • 跟知乎一样的网站做展示网站步骤
  • 邯郸网站建设效果好wordpress app 加载慢
  • 做app的网站有哪些功能广州自适应网站建设
  • 兰州建设网站的网站开源网站建设
  • 深圳网站建设南山指数基金是什么意思