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

dede修改网站密码网站模版建设

dede修改网站密码,网站模版建设,ccyycom服务器,商城网站开发用什么框架目录类和对象C static_cast、dynamic_cast、const_cast和reinterpret_cast1、为什么要引入这四种类型转化#xff1f;2、应用场景。C/C类型转换的本质struct和class的区别为什么会诞生面向对象的编程思想析构函数的执行时机初始化 const 成员变量C const对象#xff08;常对象… 目录类和对象C static_cast、dynamic_cast、const_cast和reinterpret_cast1、为什么要引入这四种类型转化2、应用场景。C/C类型转换的本质struct和class的区别为什么会诞生面向对象的编程思想析构函数的执行时机初始化 const 成员变量C const对象常对象Student stu()和Student stu的区别C函数编译原理拷贝构造函数、赋值构造函数移动构造函数new、delete、malloc()、free()C对象的内存模型C继承时的对象内存模型封闭类——包含成员对象的类为什么要有this指针C static静态成员变量详解C static静态成员函数详解C友元函数和友元类C friend关键字C class和struct到底有什么区别C string的内部究竟是什么样的借助指针突破访问权限的限制访问private、protected属性的成员变量C类成员的访问权限继承与派生继承虚继承C虚继承下的内存模型C多态与虚函数C将派生类赋值给基类向上转型虚函数—实现多态的一个工具多态为什么会有虚析构函数C纯虚函数抽象类虚函数表typeid运算符RTTI机制静态绑定和动态绑定C运算符重载operator运算符重载函数不能有默认的参数以哪种方式重载运算符重载输入输出运算符重载下标运算符[]模板函数模板类模板C异常处理C输入输出流C多文件编程如何防止头文件被重复引入C const常量如何在多文件编程中使用头文件中一般写什么STL中hashtable的底层实现STL中vector的底层实现C语言位域位段详解左值引用、右值引用C语言内存对齐C/C 代码生成可执行文件的过程GCC、gcc、g的区别C命名空间名字空间详解声明的含义externC中的const相比C发生的变化内联函数函数重载extern Cc源文件中要包含自己的头文件C引用类和对象 C static_cast、dynamic_cast、const_cast和reinterpret_cast 语法xxx_castnewType(data) 1、为什么要引入这四种类型转化 答C语言中强制类型转换很简单(new type)。但是这样做有缺点语义不明确不利于代码审查可读性很差。 const int n 3; int *p (int*)n;比如上面两行代码我们从第二行代码根本不知道发生了什么样的类型转换。因此C引入了这四种强制类型转换增强了代码的可读性。 2、应用场景。 1static_cast用于相近类型之间的转换编译器隐式执行的任何类型转换都可用static_cast但它不能用于两个不相关类型之间转换。 2const_cast用于删除变量的const属性转换后就可以对const变量的值进行修改。 3dynamic_cast用于在类的继承层次之间进行类型转换它既允许向上转型Upcasting也允许向下转型Downcasting。向上转型是无条件的不会进行任何检测所以都能成功向下转型的前提必须是安全的要借助 RTTI 进行检测所以只有一部分能成功。只能转换指针类型和引用类型参考 4reinterpret_cast类似C语言中的强制类型转换reinterpret顾名思义重新解释的意思即对内存中的数据重新解释。 C/C类型转换的本质 数据是存在内存中的数据的类型就是解释数据的方式数据类型转换就是对内存中的数据重新做出解释。 struct和class的区别 C语言中的 struct 只能包含变量而 C 中的 class 除了可以包含变量还可以包含函数。 为什么会诞生面向对象的编程思想 举一个例子说明你想写一个计算器的小程序可以完成加减乘除四种运算可以写四个函数把这四个函数放在一个源文件中并提供一个头文件屏蔽了源码细节同时也保护了自己的知识产权别人就可以调用它。 接着你要写一个操作系统的大型程序而前面写的计算器是操作系统中的一个小工具同时会有很多像计算器的小工具你当然可以一个小工具写一个源文件但是这样源码文件会有很多更好地做法是写一个小工具集合源文件里面写很多小工具类这样就可以用一个源文件存放很多小工具。而且一个小工具就是一个类很容易区分符合人的思维习惯就是为了方便人思考。 析构函数的执行时机 析构函数在对象被销毁时调用。 全局对象在内存的全局数据区程序结束时调用这些对象的析构函数。函数内部创建的对象在栈区函数执行结束时调用。new出来的对象在堆区delete时调用。 初始化 const 成员变量 只能使用初始化列表。当然在类内定义的时候也可以赋初值但是在编码阶段就指定值并不适用所有情景。 C const对象常对象 为什么常对象只能使用常成员函数 因为非const成员函数可能会修改成员变量的值。本质常对象禁止修改它的成员变量。 Student stu()和Student stu的区别 他们都是调用无参构造函数无区别。 C函数编译原理 函数重命名 C中的函数在编译时会根据它所在的命名空间、它所属的类、以及它的参数列表也叫参数签名等信息进行重新命名形成一个新的函数名。成员函数最终编译成全局函数如果成员函数中用到了成员变量该怎么办呢成员变量的作用域不是全局编译成员函数时会额外添加一个参数this把当前对象的地址传进去以此来让成员函数找到成员变量。this 实际上是成员函数的一个形参在调用成员函数时将对象的地址作为实参传递给 this。 拷贝构造函数、赋值构造函数 对象不存在且没用别的对象来初始化就是调用了构造函数 对象不存在且用别的对象来初始化就是拷贝构造函数 对象存在用别的对象来给它赋值就是赋值函数。 初始化对象是指为对象分配内存后第一次向内存中填充数据这个过程会调用构造函数。只要创建对象就会调用构造函数。 拷贝构造函数只有一个参数它的类型是当前类的引用而且一般都是 const 引用。 1为什么必须是当前类的引用呢 如果拷贝构造函数的参数不是当前类的引用而是当前类的对象那么在调用拷贝构造函数时会将另外一个对象直接传递给形参这本身就是一次拷贝会再次调用拷贝构造函数然后又将一个对象直接传递给了形参将继续调用拷贝构造函数……这个过程会一直持续下去没有尽头陷入死循环。 2为什么是 const 引用呢不管是const对象还是非const对象都可以用来初始化当前对象 拷贝构造函数的目的是用其它对象的数据来初始化当前对象并没有期望更改其它对象的数据添加 const 限制后这个含义更加明确了。 另外一个原因是添加 const 限制后可以将 const 对象和非 const 对象传递给形参了因为非 const 类型可以转换为 const 类型。如果没有 const 限制就不能将 const 对象传递给形参因为 const 类型不能转换为非 const 类型这就意味着不能使用 const 对象来初始化当前对象了。 如果程序员没有显式地定义拷贝构造函数那么编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数很简单就是使用“老对象”的成员变量对“新对象”的成员变量进行一一赋值。但是对于深拷贝默认拷贝构造函数就不够用了。 对于基本类型的数据我们很少会区分「初始化」和「赋值」这两个概念即使将它们混淆也不会出现什么错误。但是对于类它们的区别就非常重要了因为初始化时会调用构造函数以拷贝的方式初始化时会调用拷贝构造函数而赋值时会调用重载过的赋值运算符。对象被创建后必须立即被初始化。 这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝我们必须显式地定义拷贝构造函数才能达到深拷贝的目的。 如果一个类拥有指针类型的成员变量那么绝大部分情况下就需要深拷贝因为只有这样才能将指针指向的内容再复制出一份来让原有对象和新生对象相互独立彼此之间不受影响。如果类的成员变量没有指针一般浅拷贝足以。 C深拷贝和浅拷贝深复制和浅复制完全攻略 移动构造函数 所谓移动语义指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解移动语义指的就是将其他对象通常是临时对象拥有的内存资源“移为已用”。事实上对于程序执行过程中产生的临时对象往往只用于传递数据没有其它的用处并且会很快会被销毁。因此在使用临时对象初始化新对象时我们可以将其包含的指针成员指向的内存资源直接移给新对象所有无需再新拷贝一份这大大提高了初始化的执行效率。在实际开发中通常在类中自定义移动构造函数的同时会再为其自定义一个适当的拷贝构造函数由此当用户利用右值初始化类对象时会调用移动构造函数使用左值非右值初始化类对象时会调用拷贝构造函数。std::move 的作用是无论你传给它的是左值还是右值通过 std::move 之后都变成了右值。i 是左值i 是右值。 前者对 i 1 后再赋给 i最终的返回值就是 i所以i 的结果是具名的名字就是 i而对于 i 而言是先对 i 进行一次拷贝将得到的副本作为返回结果然后再对 i 1由于 i 的结果是对 i 1前 i 的一份拷贝所以它是不具名的。假设自增前i的值是 6那么i 得到的结果是 7这个 7 有个名字就是 i 而 i 得到的结果是 6这个 6 是 i 1 前的一个副本它没有名字i 不是它的名字i 的值此时也是 7。可见i 和 i 都达到了使 i 1的目的但两个表达式的结果不同。 参考 new、delete、malloc()、free() new和delete是C里的关键字。malloc()和free()是C语言里的函数。 #includeiostream #includestdio.h #includestdlib.hint main() {// newint *p new int;*p 5;printf(%d\n,*p);delete p;int *pp new int[5];for (int i0;i5;i){pp[i]i1;printf(%d ,pp[i]);}delete[] pp;// malloc// char *pp (char*)malloc(sizeof(char)*15);// pp[0]h;pp[1]e;pp[2]l;pp[3]l;pp[4]o;pp[5]0;// printf(%s\n,pp);//free// free(pp);return 0; }C对象的内存模型 类是创建对象的模板不占用内存空间不存在于编译后的可执行文件中而对象是实实在在的数据需要内存来存储。对象被创建时会在栈区或者堆区分配内存。 编译器会将成员变量和成员函数分开存储分别为每个对象的成员变量分配内存但是所有对象都共享同一段函数代码。成员变量在堆区或栈区分配内存成员函数在代码区分配内存。 对象所占用的内存仅仅包含了成员变量。sizeof(对象) 类可以看做是一种复杂的数据类型也可以使用 sizeof 求得该类型的大小。从运行结果可以看出在计算类这种类型的大小时只计算了成员变量的大小并没有把成员函数也包含在内。 C继承时的对象内存模型 在派生类的对象模型中会包含所有基类的成员变量。这种设计方案的优点是访问效率高能够在派生类对象中直接访问基类变量无需经过好几层间接计算。 基类的成员变量排在前面派生类的排在后面。 封闭类——包含成员对象的类 构造函数执行顺序。 先执行成员对象的构造函数再执行封闭类自己的构造函数。析构函数的执行顺序。 先构造的后析构。 为什么要有this指针 用于关联成员函数和成员变量。请见前文C函数编译原理。 C static静态成员变量详解 静态成员变量可以实现多个对象共享数据的目标。在内存中只有一份。类内声明类外初始化不加staticint Student::m_total 0;。内存分配的时机。 在类外初始化时分配内存也就是说没有在类外初始化的静态成员变量不能使用。静态成员变量不占用对象的内存在全局数据区分配内存。 C static静态成员函数详解 静态成员函数的形参中不会添加this因此无法访问非静态成员非静态成员函数也不行因为该函数内部可能会访问非静态成员没有this根本访问不到。一般通过类来调用。声明和定义与静态成员变量一样。 C友元函数和友元类C friend关键字 理解你给你的朋友授权声明友元他可以进你家访问你的成员变量。 C class和struct到底有什么区别 成员的默认访问权限不同。 class默认为privatestruct默认为public默认的继承方式不同。 class默认为private继承struct默认为public继承。class 可以使用模板而 struct 不能。 C string的内部究竟是什么样的 string可以和C风格字符串混用这体现了C兼容C的特点。 C标准没有定义string的内存布局由编译器厂商自己实现。一种内存分配方式——引用计数。 对有几个人引用他做一个计数这样避免了存在同一数据的多个副本。 copy-on-write策略当字符串修改的时候才创建各自的拷贝。 借助指针突破访问权限的限制访问private、protected属性的成员变量 C 的成员访问权限仅仅是语法层面上的是指访问权限仅对取成员运算符.和-起作用而无法防止直接通过指针来访问。 本节的目的不是为了访问到 private、protected 属性的成员变量这种“花拳绣腿”没有什么现实的意义本节主要是让大家明白编译器内部的工作原理以及指针的灵活运用。 通过指针偏移来访问成员。 参考 C类成员的访问权限 在类的内部定义类的代码内部无论成员被声明为 public、protected 还是 private都是可以互相访问的没有访问权限的限制。 在类的外部定义类的代码之外只能通过对象访问成员并且通过对象只能访问 public 属性的成员不能访问 private、protected 属性的成员。 注意点下面代码中operator 函数是complex 类的成员函数在类的内部A.m_real 是可以访问到的。 继承与派生 继承 继承Inheritance可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A那么 B 就拥有 A 的成员变量和成员函数。语法class 派生类名:继承方式 基类名{派生类新增加的成员 };继承方式限定了基类成员在派生类中的访问权限包括 public公有的、private私有的和 protected受保护的。此项是可选项如果不写默认为 private成员变量和成员函数默认也是 private。三种继承方式 继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。 不管继承方式如何基类中的 private 成员在派生类中始终不能使用不能在派生类的成员函数中访问或调用。 注意我们这里说的是基类的 private 成员不能在派生类中使用并没有说基类的 private 成员不能被继承。实际上基类的 private 成员是能够被继承的并且成员变量会占用派生类对象的内存它只是在派生类中不可见导致无法使用罢了。private 成员的这种特性能够很好的对派生类隐藏基类的实现以体现面向对象的封装性。 由于 private 和 protected 继承方式会改变基类成员在派生类中的访问权限导致继承关系复杂所以实际开发中我们一般使用 public。 改变访问权限应用场景呢 使用 using 关键字可以改变基类成员在派生类中的访问权限例如将 public 改为 private、将 protected 改为 public。 注意using 只能改变基类中 public 和 protected 成员的访问权限不能改变 private 成员的访问权限因为基类中 private 成员在派生类中是不可见的根本不能使用所以基类中的 private 成员在派生类中无论如何都不能访问。 参考 实际上就两个方向升权限protected 改为 public和降权限public 改为 private。这样做增加了访问权限的灵活性。 虚继承 虚继承的本质让某个类做出声明承诺愿意共享它的基类。 虚继承和普通继承的一个区别参见3。 1、为了解决多继承时的命名冲突和冗余数据问题例如菱形继承C 提出了虚继承使得在派生类中只保留一份间接基类虚基类的成员。 在继承方式前面加上 virtual 关键字就是虚继承 2、可以看到使用多继承经常会出现二义性问题必须十分小心。上面的例子是简单的如果继承的层次再多一些关系更复杂一些程序员就很容易陷人迷魂阵程序的编写、调试和维护工作都会变得更加困难因此我不提倡在程序中使用多继承只有在比较简单和不易出现二义性的情况或实在必要时才使用多继承能用单一继承解决的问题就不要使用多继承。也正是由于这个原因C 之后的很多面向对象的编程语言例如 Java、C#、PHP 等都不支持多继承。 参考 3、C 规定必须由最终的派生类 D 来初始化虚基类 A直接派生类 B 和 C 对 A 的构造函数的调用是无效的。D只保留一份数据的话没必要让B和C构造A了况且 B 和 C 在调用 A 的构造函数时很有可能给出不同的实参这个时候编译器就会犯迷糊不知道使用哪个实参初始化 m_a。参考 4、 注意如果类A1和类A2都有成员m_a但他俩并不是继承自同一个类那么继承C就算虚继承他们也还是有两份m_a。 C虚继承下的内存模型 对于普通继承基类成员变量始终在派生类成员变量的前面而且不管继承层次有多深它相对于派生类对象顶部的偏移量是固定的。 而对于虚继承恰恰和普通继承相反大部分编译器会把基类成员变量放在派生类成员变量的后面这样随着继承层级的增加基类成员变量的偏移就会改变就得通过其他方案来计算偏移量。 虚基类表本质上就是一个数组存放各个虚基类子对象的偏移地址。参考 构造函数的调用顺序还是和普通继承一样先调用父类再调用子类。 内存模型则不同先放指向虚基类表的指针再放自己的成员变量最后放虚基类的子对象。 不管是虚基类的直接派生类还是间接派生类虚基类的子对象始终位于派生类对象的最后面。 C多态与虚函数 C将派生类赋值给基类向上转型 包括指针的赋值对象的赋值引用的赋值。 赋值的本质是将现有的数据写入已分配好的内存中对象的内存只包含了成员变量所以对象之间的赋值是成员变量的赋值成员函数不存在赋值问题。 编译器通过指针来访问成员变量指针指向哪个对象就使用哪个对象的数据编译器通过指针的类型来访问成员函数指针属于哪个类的类型就使用哪个类的函数。 为了使用基类指针访问派生类的成员函数引入了虚函数。 虚函数—实现多态的一个工具 在父类和子类的成员函数子类重写了父类的成员函数前加上virtual就可以实现使用基类指针调用派生类的成员函数。 重写函数的声明相同实现不同。 可以只将基类中的函数声明为虚函数。 多态 生物学定义同一物种中不同形态的个体。龙生九子形态各异 直观理解想象一个函数根据传入的参数不同执行的逻辑和结果也不同。 为什么会有虚析构函数 应用场景当子类的构造函数中new了一段内存空间当使用父类指针指向子类对象delete该指针时只调用了父类的析构函数而没有调用子类的析构函数导致内存泄漏。 将父类的析构函数申明为虚函数时就会先调用子类的析构函数子类的析构函数又会调用父类的析构函数。 C纯虚函数 语法virtual 返回值类型 函数名 (函数参数) 0; 无函数体只有声明。 抽象类 包含纯虚函数的类称为抽象类。无法创建对象 虚函数表 问题为什么编译器能通过指针指向的对象找到虚函数 答因为在创建对象的时候增加了虚函数表。如果一个类包含有虚函数那么在创建对象的时候就会额外创建一个数组虚函数表数组里的每一个元素都是虚函数的入口地址。但是数组和对象是分开存的对象中有一个指针指向数组的首地址。 typeid运算符 可以求一个表达式的类型常用来判断两个类型是否相等。 用法例子。有点像Java中的isInstance()。 CFather *son new CSon; if (typeid(*son) typeid(CSon))cout1endl;RTTI机制 Run-Time Type Identification 运行时类型识别。 用父类指针指向子类对象时有时候编译器在编译期没法确定该指针指向哪个对象即不能确定*p的类型。只有程序运行之后才能确定这就叫运行时类型识别。参考 底层原理根据对象指针找到虚函数表的地址再找到当前类对应的 type_info 对象就能知道当前对象是哪个类的对象就能调用相应的被重写的成员函数。 编译器会在虚函数表 vftable 的开头插入一个指针指向当前类对应的 type_info 对象 在 C 中只有类中包含了虚函数时才会启用 RTTI 机制其他所有情况都可以在编译阶段确定类型信息。 静态绑定和动态绑定 我们不妨将变量名和函数名统称为符号Symbol找到符号对应的地址的过程叫做符号绑定。 编译期就能确定符号对应的地址就是静态绑定。 等到程序运行的时候才能确定符号对应的地址就叫动态绑定。 C运算符重载operator 本质上就是函数重载。参考 运算符重载函数不能有默认的参数 运算符重载函数不能有默认的参数否则就改变了运算符操作数的个数这显然是错误的。 C默认参数实参给形参传值是从左到右依次匹配的。一旦某个形参有了默认值那么它后面的形参也必须有默认值 有了默认参数按理说就可以少传一些参数而使用默认值但是这违背了运算符原本的性质。比如号两边必须有东西 以哪种方式重载运算符 重载运算符的两种方式成员函数全局函数友元函数。 全局函数方式的应用场景。保证参数的对称性 类的成员函数不能对称的处理数据。 以成员函数方式重载只能计算c15.6c.operator(Complex(15.6)) c是complex类的对象且该类中存在一个参数的构造函数所以可以把15.6 转为为complex对象不能计算15.6c 。(15.6).operator(c) 是错误的C 只会对成员函数的参数进行类型转换而不会对调用成员函数的对象进行类型转换。 不禁会问了为什么不能对double类型也定义运算符重载呢如果double中也重载了operator 不就可以完成上面不能完成的运算了嘛 C 创始人 Bjarne Stroustrup 也曾考虑过为内部类型bool、int、double 等定义额外运算符的问题但后来还是放弃了这种想法因为 Bjarne Stroustrup 不希望改变现有规则任何类型无论是内部类型还是用户自定义类型都不能在其定义完成以后再增加额外的操作。这里还有另外的一个原因C内部类型之间的转换已经够肮脏了决不能再向里面添乱。而通过成员函数为已存在的类型提供混合运算的方式从本质上看比我们所采用的全局函数友元函数加转换构造函数的方式还要肮脏许多。 成员函数方式的应用场景。 我们首先要明白运算符重载的初衷是给类添加新的功能方便类的运算它作为类的成员函数是理所应当的是首选的。 C 规定箭头运算符-、下标运算符[ ]、函数调用运算符( )、赋值运算符只能以成员函数的形式重载。 重载输入输出运算符 // 1、在complex类中申明友元函数 // 2、重载输入运算符 istream operator(istream in, complex A) {inA.m_realA.m_imag;return in; }// 1、在complex类中申明友元函数 // 2、重载输出运算符 ostream operator(ostream out, complex A) {outA.m_real A.m_imagiendl;return out; } 重载下标运算符[] C 规定下标运算符[ ]必须以成员函数的形式进行重载。 两种声明格式。 返回值类型 operator[] (参数); // 既可以访问元素也可以修改元素 const 返回值类型 operator[] (参数) const; // 只能访问不能修改实际开发中应该同时提供这两种形式。第二种形式最后的const修饰整个函数表示这是一个const成员函数const对象只能调用const成员函数所以提供这种形式是有必要的。const对象表示该对象不可修改所以返回值应该也为const。这就是写两个const的原因。 模板 函数模板 template关键字用于定义函数模板typename用于声明类型参数也可以写成class。 templatetypename T void swap1(T a, T b) {T c a;a b;b c; }类模板 注意成员函数也要写模板头。类名后面要写类型参数1类型参数2。 templatetypename T1, typename T2 class Point{ public:Point(T1 x, T2 y): m_x(x), m_y(y) {}public:T1 getX() const;void setX(T1 x);T2 getY() const;void setY(T2 y);private:T1 m_x;T2 m_y; };templatetypename T1, typename T2 T1 PointT1, T2::getX() const {return m_x; }templatetypename T1, typename T2 void PointT1, T2::setX(T1 x) {m_x x; }templatetypename T1, typename T2 T2 PointT1, T2::getY() const {return m_y; }templatetypename T1, typename T2 void PointT1, T2::setY(T2 y) {m_y y; }int main() {Pointint, int p1(10,20);coutxp1.getX()yp1.getY()endl;Pointint, char* p2(10, 东京180度);coutxp2.getX()yp2.getY()endl;Pointchar*, char* *p3 new Pointchar*, char*(东京180度, 北纬210度);coutxp3-getX()yp3-getY()endl;return 0; }C异常处理 C 语言本身以及标准库中的函数抛出的异常都是 exception 类或其子类的异常。 C输入输出流 C输入输出流本质上就是已经定义好的类对象之所以称它们为流C 开发者认为数据传输包含输入和输出的过程像水一样从一个地方流到另一个地方所以称实现输入的为输入流实现数据输出的为输出流。 参考 C多文件编程 C项目的文件大致可以分为两类.h文件、.cpp文件。 .h 文件又称“头文件”用于存放常量、函数的声明部分、类的声明部分 .cpp 文件又称“源文件”用于存放变量、函数的定义部分类的实现部分。 这两种文件除了后缀不一样便于区分和管理外其他的几乎相同。区分两者并不是C语法的规定而是约定俗称的规范。 如何防止头文件被重复引入 1、条件编译。 #ifndef _STUDENT_H #define _STUDENT_H class Student {//...... }; #endif编译效率低可移植性好。一般使用这个。 2、使用#pragma once避免重复引入。 特点写在文件最开头位置#pragma once 只能作用于某个具体的文件而无法向 #ifndef 那样仅作用于指定的一段代码。编译效率高可移植性差。 3、使用_Pragma操作符。 将_Pragma(once)写在文件开头。 综合1和2兼顾可移植性和编译效率可以按下面的方式写。当编译器可以识别 #pragma once 时则整个文件仅被编译一次反之即便编译器不识别 #pragma once 指令此时仍有 #ifndef 在发挥作用。 #pragma once #ifndef _STUDENT_H #define _STUDENT_H class Student {//...... }; #endifC const常量如何在多文件编程中使用 const的功能1、表明其修饰的变量为常量。 2、将所修饰变量的可见范围限制为当前文件。 那么如何定义 const 常量才能在其他文件中使用呢参考 1将const常量定义在.h头文件中。 当包含该头文件时const常量自然也被包含进来。 头文件中一般写什么 .h 头文件的作用就是被其它的 .cpp 包含进去其本身并不参与编译但实际上它们的内容会在多个 .cpp 文件中得到编译。 申明可以多次但定义只能一次因此头文件中应该只放变量和函数的声明而不能放它们的定义。但是有三种情况例外以下三种情况属于定义但应该放在.h文件中。 1头文件中可以定义 const 和static对象。 解释因为没有用extern关键字声明的const对象仅在当前文件可见即使被包含进多个文件也不会出现重复定义的错误。 2头文件中可以定义内联函数。 解释内联函数在编译阶段就被展开了编译器必须在编译时就找到内联函数的完整定义普通函数都是先声明在链接放在头文件中刚刚好。 3头文件中可以定义类。 因为在程序中创建一个类的对象时编译器只有在这个类的定义完全可见的情况下才能知道这个类的对象应该如何布局所以关于类的定义的要求跟内联函数是基本一样的即把类的定义放进头文件在使用到这个类的.cpp文件中去包含这个头文件。 STL中hashtable的底层实现 STL中vector的底层实现 1、vector 容器在申请更多内存的同时容器中的所有元素可能会被复制或移动到新的内存地址这会导致之前创建的迭代器失效。 2、vector 容器还提供了 2 个成员函数即 front() 和 back()它们分别返回 vector 容器中第一个和最后一个元素的引用通过利用这 2 个函数返回的引用可以访问甚至修改容器中的首尾元素。 3、vector的reserve()和resize()的区别reserve是预留的意思value.reserve(20);即预留20个元素的空间capacity变为20size不变。 value.resize(21)将元素个数改变为 21 个所以会增加 一些默认初始化的元素。size变为21capacity也可能改变。 可以看到仅通过 reserve() 成员函数增加 value 容器的容量其大小并没有改变但通过 resize() 成员函数改变 value 容器的大小它的容量可能会发生改变。另外需要注意的是通过 resize() 成员函数减少容器的大小多余的元素会直接被删除不会影响容器的容量。 4、另外需要指明的是当 vector 的大小和容量相等sizecapacity也就是满载时如果再向其添加元素那么 vector 就需要扩容。vector 容器扩容的过程需要经历以下 3 步 完全弃 用现有的内存空间重新申请更大的内存空间将旧内存空间中的数据按原有顺序移动到新的内存空间中最后将旧的内存空间释放。 5、emplace_back()c11新增和push_back()的区别 emplace_back() 和 push_back() 的区别就在于底层实现的机制不同。push_back() 向容器尾部添加元素时首先会创建这个元素然后再将这个元素拷贝或者移动到容器中如果是拷贝的话事后会自行销毁先前创建的这个元素而 emplace_back() 在实现时则是直接在容器尾部创建这个元素省去了拷贝或移动元素的过程。 push_back() 在底层实现时会优先选择调用移动构造函数如果没有才会调用拷贝构造函数。 显然完成同样的操作push_back() 的底层实现过程比 emplace_back() 更繁琐换句话说emplace_back() 的执行效率比 push_back() 高。因此在实际使用时建议大家优先选用 emplace_back()。 参考 C语言位域位段详解 左值引用、右值引用 左值有名字可以取地址。 右值无名字不能取地址。临时对象、字面值。 “在C之中的变量只有左值与右值两种其中凡是可以取地址的变量就是左值而没有名字的临时变量字面量就是右值”。 正是因为这两种变量分别位于 的左右两侧所以被命名为左值与右值。 左值引用 int num 10; int b num; //正确 int c 10; //错误右值引用 int num 10; //int a num; //右值引用不能初始化为左值 int a 10;右值引用主要用于移动语义和完美转发其中前者需要有修改右值的权限。将亡值是C11为了引入右值引用而提出的概念(因此传统C中纯右值和右值是同一个概念)也就是即将被销毁、却能够被移动的值。 参考 C语言内存对齐 为了提高寻址效率。以空间换时间。 将一个数据尽量放在一个步长CPU的一次寻址之内避免跨步长存储这称为内存对齐。 CPU 通过地址总线来访问内存一次能处理几个字节的数据就命令地址总线读取几个字节的数据。32 位的 CPU 一次可以处理4个字节的数据那么每次就从内存读取4个字节的数据。64位的处理器也是这个道理每次读取8个字节。 最后需要说明的是内存对齐不是C语言的特性它属于计算机的运行原理C、Java、Python等其他编程语言同样也会有内存对齐的问题。 参考 C/C 代码生成可执行文件的过程 GCC、gcc、g的区别 GCC 是由 GUN 组织开发的一个编译器套件支持很多语言。 gcc是一个通用命令它会根据不同的参数调用不同的编译器或链接器。也就是说你可以用该命令编译c或者别的语言。 为了方便 GCC 又针对不同的语言推出了不同的命令g命令用来编译 Cgcj命令用来编译 Javagccgo命令用来编译Go语言。 C命名空间名字空间详解 一个中大型软件往往由多名程序员共同开发会使用大量的变量和函数不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过没有问题时将它们结合到一起就有可能会出现命名冲突。 为了解决合作开发时的命名冲突问题C 引入了命名空间Namespace的概念。 使用变量、函数时要指明它们所在的命名空间。 很多教程中都是这样做的将 std 直接声明在所有函数外部这样虽然使用方便但在中大型项目开发中是不被推荐的这样做增加了命名冲突的风险我推荐在函数内部声明 std。参考 声明的含义 我们知道C语言代码是由上到下依次执行的不管是变量还是函数原则上都要先定义再使用否则就会报错。但在实际开发中经常会在函数或变量定义之前就使用它们这个时候就需要提前声明。 所谓声明Declaration就是告诉编译器我要使用这个变量或函数你现在没有找到它的定义不要紧请不要报错稍后我会把定义补上。 例如我们知道使用 printf()、puts()、scanf()、getchar() 等函数要引入 stdio.h 这个头文件很多初学者认为 stdio.h 中包含了函数定义也就是函数体只要有了头文件程序就能运行。其实不然头文件中包含的都是函数声明而不是函数定义函数定义都在系统库中只有头文件没有系统库在链接时就会报错程序根本不能运行。 extern 对于函数声明来说有没有 extern 都是一样的。因为函数的定义有函数体函数的声明没有函数体编译器很容易区分定义和声明。 变量和函数不同编译器只能根据 extern 来区分有 extern 才是声明没有 extern 就是定义。 extern 是“外部”的意思很多教材讲到extern 用来声明一个外部其他文件中的变量或函数也就是说变量或函数的定义在其他文件中。不过我认为这样讲不妥因为除了定义在外部定义在当前文件中也是正确的。例如将 module.c 中的int m 100;移动到 main.c 中的任意位置都是可以的。所以我认为extern 是用来声明的不管具体的定义是在当前文件内部还是外部都是正确的。 参考 C中的const相比C发生的变化 赋值原理不同。 C中的 const 更像编译阶段的 #define预处理阶段替换C语言中会读内存再赋值C不读内存直接在编译阶段替换。可见范围发生改变。 C中全局 const 变量的可见范围是当前文件。注意普通全局变量的作用域是当前文件但在别的文件中也是可见的在别的文件中通过extern申明后就可以使用。而 const 变量就算在其他文件中用extern声明后也不能用。但是可以在当前文件中定义的时候加上extern关键字来解决。 参考 内联函数 为了消除函数调用的开销产生了内联函数。注意只有在函数执行时间和调用时间差不多的时候才需要考虑函数调用的开销。换句话说内联函数适用于函数体比较小的情况。另外因为带参数的宏替换很容易犯错所以内联函数也用于替代宏定义。内联函数更像是编译期间的宏字符串级别的替换。建议直接定义在头文件中注意内联函数的定义和声明放在不同文件中会报错。重复包含也没关系因为它在编译阶段就被展开了。内联函数的代码在编译后就被消除了不存在于虚拟地址空间中没法重复使用。只是程序员对编译器的一个建议编译器不一定会采纳。 函数重载 一同函数名必须相同。 一不同参数列表必须不同。 返回值无要求 extern “C” 在C代码中调用C语言函数由于编译方式的不同函数重命名方式不同导致找不到调用的函数实现。因此加上extern “C” 关键字来告诉编译器用处理C语言代码的方式处理C代码。参考 c源文件中要包含自己的头文件 是为了检查声明和定义的一致性只有声明和定义在一个文件中编译器才会进行一致性检查否则有可能在运行的时候出现不好排查的bug。参考 C引用 引用是对指针的封装引用占用的内存和指针占用的内存长度一样。让代码书写变简洁。 和指针的区别。 1引用在定义时必须初始化以后不能再指向别的数据指针定义时无需初始化以后也可以改变指向。 2有const指针但是没有const引用因为规定引用只能从一而终的指向一个数据用const修饰多此一举。 3有多级指针的概念无多级引用。引用不能指代临时数据。 引用可以理解为别名临时数据连名字都没有哪来的别名。 易错点当引用作为函数的形参时自然不能传递临时数据没有名字的数据。将常引用绑定到临时数据时编译器采取了一种妥协机制编译器会为临时数据创建一个新的、无名的临时变量并将临时数据放入该临时变量中然后再将引用绑定到该临时变量。 因此将形参定义为常引用以便可以接收临时数据。普通引用不能绑定到临时数据也不能绑定到相近的数据类型可以自动转换的。但是常引用可以原理创建临时变量将引用绑定到这个临时变量。概括起来说将引用类型的形参添加 const 限制的理由有三个 使用 const 可以避免无意中修改数据的编程错误 使用 const 能让函数接收 const 和非 const 类型的实参否则将只能接收非 const 类型的实参 使用 const 引用能够让函数正确生成并使用临时变量。
http://www.w-s-a.com/news/201562/

相关文章:

  • 东莞网站优化效果如何网络设计工作
  • 网站备案系统验证码出错的解决方案任丘建设银行网站
  • 个人博客建站wordpress叮当app制作
  • 网站式的公司记录怎么做二手书网站策划书
  • 营销型网站的建设重点是什么帝国程序和WordPress
  • 正能量网站推荐不需要下载巴中网站建设开发公司
  • 学生模拟网站开发西安seo平台
  • 免费的app推广平台免费网站seo
  • 建一个个人网站网站建设中小企业广西
  • 优惠券网站做淘客违规吗个人建网站运营.
  • 旅游网站制作建设华大基因 网站建设
  • sem推广竞价托管南京seo网站优化
  • 网站优化网站建站教程网站建设 成都
  • 网站 配色表html代码在线
  • 城乡和建设部建造师网站众筹平台网站建设
  • 外贸网站模板免费下载微网站制作软件
  • 一个新的网站怎么做宣传技术先进的网站建
  • 福建网站建设有限公司需求网站
  • 生物科技企业网站做的比较好的企业培训网站模板
  • 南京 高端网站建设网站备案密码怎么找回
  • 蛋糕店网站模板建设电子商务系统网站
  • 海口网站建设优化公司网站开发要加班吗
  • 建设一个网站需要注意哪些要求群晖的网站开发
  • 精通网站开发阅读网页视频下载慢怎么办
  • 网站标题的选择巴音郭楞库尔勒网站建设
  • 成都市网站建设服务商怎么进网站后台管理系统
  • 企业网站站内优化30岁做网站编辑
  • 与安网站建设网站建设征求意见稿
  • 学校网站推广做网站手把手
  • 网站开发遇到的难题wordpress文章调用