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

企业软件定制开发公司宁波网站seo哪家好

企业软件定制开发公司,宁波网站seo哪家好,电子商务网站建设课程心得,网站首页做30个关键词const 作用 修饰变量#xff0c;说明该变量不可以被改变#xff1b;修饰指针#xff0c;分为指向常量的指针#xff08;pointer to const#xff09;和自身是常量的指针#xff08;常量指针#xff0c;const pointer#xff09;#xff1b;修饰引用#xff0c;指向…const 作用 修饰变量说明该变量不可以被改变修饰指针分为指向常量的指针pointer to const和自身是常量的指针常量指针const pointer修饰引用指向常量的引用reference to const用于形参类型即避免了拷贝又避免了函数对值的修改修饰成员函数说明该成员函数内不能修改成员变量。 const 的指针与引用 指针 指向常量的指针pointer to const自身是常量的指针常量指针const pointer 引用 指向常量的引用reference to const没有 const reference因为引用只是对象的别名引用不是对象不能用 const 修饰 为了方便记忆可以想成被 const 修饰在 const 后面的值不可改变如下文使用例子中的 p2、p3 使用 const 使用 // 类 class A { private:const int a; // 常对象成员可以使用初始化列表或者类内初始化public:// 构造函数A() : a(0) { };A(int x) : a(x) { }; // 初始化列表// const可用于对重载函数的区分int getValue(); // 普通成员函数int getValue() const; // 常成员函数不得修改类中的任何数据成员的值 };void function() {// 对象A b; // 普通对象可以调用全部成员函数const A a; // 常对象只能调用常成员函数const A *p a; // 指针变量指向常对象const A q a; // 指向常对象的引用// 指针char greeting[] Hello;char* p1 greeting; // 指针变量指向字符数组变量const char* p2 greeting; // 指针变量指向字符数组常量const 后面是 char说明指向的字符char不可改变char* const p3 greeting; // 自身是常量的指针指向字符数组变量const 后面是 p3说明 p3 指针自身不可改变const char* const p4 greeting; // 自身是常量的指针指向字符数组常量 }// 函数 void function1(const int Var); // 传递过来的参数在函数内不可变 void function2(const char* Var); // 参数指针所指内容为常量 void function3(char* const Var); // 参数指针为常量 void function4(const int Var); // 引用参数在函数内为常量// 函数返回值 const int function5(); // 返回一个常数 const int* function6(); // 返回一个指向常量的指针变量使用const int *p function6(); int* const function7(); // 返回一个指向变量的常指针使用int* const p function7();宏定义 #define 和 const 常量 宏定义 #defineconst 常量宏定义相当于字符替换常量声明预处理器处理编译器处理无类型安全检查有类型安全检查不分配内存要分配内存存储在代码段存储在数据段可通过 #undef 取消不可取消 static 作用 修饰普通变量修改变量的存储区域和生命周期使变量存储在静态区在 main 函数运行前就分配了空间如果有初始值就用初始值初始化它如果没有初始值系统用默认值初始化它。修饰普通函数表明函数的作用范围仅在定义该函数的文件内才能使用。在多人开发项目时为了防止与他人命名空间里的函数重名可以将函数定位为 static。修饰成员变量修饰成员变量使所有的对象只保存一个该变量而且不需要生成对象就可以访问该成员。修饰成员函数修饰成员函数使得不需要生成对象就可以访问该函数但是在 static 函数内不能访问非静态成员。 this 指针 this 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向调用该成员函数的那个对象。当对一个对象调用成员函数时编译程序先将对象的地址赋给 this 指针然后调用成员函数每次成员函数存取数据成员时都隐式使用 this 指针。当一个成员函数被调用时自动向它传递一个隐含的参数该参数是一个指向这个成员函数所在的对象的指针。this 指针被隐含地声明为: ClassName *const this这意味着不能给 this 指针赋值在 ClassName 类的 const 成员函数中this 指针的类型为const ClassName* const这说明不能对 this 指针所指向的这种对象是不可修改的即不能对这种对象的数据成员进行赋值操作this 并不是一个常规变量而是个右值所以不能取得 this 的地址不能 this。在以下场景中经常需要显式引用 this 指针 为实现对象的链式引用为避免对同一对象进行赋值操作在实现一些数据结构时如 list。 inline 内联函数 特征 相当于把内联函数里面的内容写在调用内联函数处相当于不用执行进入函数的步骤直接执行函数体相当于宏却比宏多了类型检查真正具有函数特性编译器一般不内联包含循环、递归、switch 等复杂操作的内联函数在类声明中定义的函数除了虚函数的其他函数都会自动隐式地当成内联函数。 使用 inline 使用 // 声明1加 inline建议使用 inline int functionName(int first, int second,...);// 声明2不加 inline int functionName(int first, int second,...);// 定义 inline int functionName(int first, int second,...) {/****/};// 类内定义隐式内联 class A {int doA() { return 0; } // 隐式内联 }// 类外定义需要显式内联 class A {int doA(); } inline int A::doA() { return 0; } // 需要显式内联编译器对 inline 函数的处理步骤 将 inline 函数体复制到 inline 函数调用点处为所用 inline 函数中的局部变量分配内存空间将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中如果 inline 函数有多个返回点将其转变为 inline 函数代码块末尾的分支使用 GOTO。 优缺点 优点 内联函数同宏函数一样将在被调用处进行代码展开省去了参数压栈、栈帧开辟与回收结果返回等从而提高程序运行速度。内联函数相比宏函数来说在代码展开时会做安全检查或自动类型转换同普通函数而宏定义则不会。在类中声明同时定义的成员函数自动转化为内联函数因此内联函数可以访问类的成员变量宏定义则不能。内联函数在运行时可调试而宏定义不可以。 缺点 代码膨胀。内联是以代码膨胀复制为代价消除函数调用带来的开销。如果执行函数体内代码的时间相比于函数调用的开销较大那么效率的收获会很少。另一方面每一处内联函数的调用都要复制代码将使程序的总代码量增大消耗更多的内存空间。inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译不像 non-inline 可以直接链接。是否内联程序员不可控。内联函数只是对编译器的建议是否对函数内联决定权在于编译器。 虚函数virtual可以是内联函数inline吗 虚函数可以是内联函数内联是可以修饰虚函数的但是当虚函数表现多态性的时候不能内联。内联是在编译期建议编译器内联而虚函数的多态性在运行期编译器无法知道运行期调用哪个代码因此虚函数表现为多态性时运行期不可以内联。inline virtual 唯一可以内联的时候是编译器知道所调用的对象是哪个类如 Base::who()这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。 虚函数内联使用 #include iostream using namespace std; class Base { public:inline virtual void who(){cout I am Base\n;}virtual ~Base() {} }; class Derived : public Base { public:inline void who() // 不写inline时隐式内联{cout I am Derived\n;} };int main() {// 此处的虚函数 who()是通过类Base的具体对象b来调用的编译期间就能确定了所以它可以是内联的但最终是否内联取决于编译器。 Base b;b.who();// 此处的虚函数是通过指针调用的呈现多态性需要在运行时期间才能确定所以不能为内联。 Base *ptr new Derived();ptr-who();// 因为Base有虚析构函数virtual ~Base() {}所以 delete 时会先调用派生类Derived析构函数再调用基类Base析构函数防止内存泄漏。delete ptr;ptr nullptr;system(pause);return 0; }volatile volatile int i 10;volatile 关键字是一种类型修饰符用它声明的类型变量表示可以被某些编译器未知的因素操作系统、硬件、其它线程等更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。volatile 关键字声明的变量每次访问时都必须从内存中取出值没有被 volatile 修饰的变量可能由于编译器的优化从 CPU 寄存器中取值const 可以是 volatile 如只读的状态寄存器指针可以是 volatile assert() 断言是宏而非函数。assert 宏的原型定义在 assert.hC、cassertC中其作用是如果它的条件返回错误则终止程序执行。可以通过定义 NDEBUG 来关闭 assert但是需要在源代码的开头include assert.h 之前。 assert() 使用 #define NDEBUG // 加上这行则 assert 不可用 #include assert.hassert( p ! NULL ); // assert 不可用sizeof() sizeof 对数组得到整个数组所占空间大小。sizeof 对指针得到指针本身所占空间大小。 #pragma pack(n) 设定结构体、联合以及类成员变量以 n 字节方式对齐 #pragma pack(n) 使用 #pragma pack(push) // 保存对齐状态 #pragma pack(4) // 设定为 4 字节对齐struct test {char m1;double m4;int m3; };#pragma pack(pop) // 恢复对齐状态位域 Bit mode: 2; // mode 占 2 位类可以将其非静态数据成员定义为位域bit-field在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或硬件设备传递二进制数据时通常会用到位域。 位域在内存中的布局是与机器有关的位域的类型必须是整型或枚举类型带符号类型中的位域的行为将因具体实现而定取地址运算符不能作用于位域任何指针都无法指向类的位域 extern “C” 被 extern 限定的函数或变量是 extern 类型的被 extern C 修饰的变量和函数是按照 C 语言方式编译和链接的 extern C 的作用是让 C 编译器将 extern C 声明的代码当作 C 语言代码处理可以避免 C 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。 extern “C” 使用 #ifdef __cplusplus extern C { #endifvoid *memset(void *, int, size_t);#ifdef __cplusplus } #endifstruct 和 typedef struct C 中 // c typedef struct Student {int age; } S; 等价于 // c struct Student { int age; };typedef struct Student S;此时 S 等价于 struct Student但两个标识符名称空间不相同。 另外还可以定义与 struct Student 不冲突的 void Student() {}。 C 中 由于编译器定位符号的规则搜索规则改变导致不同于C语言。 一、如果在类标识符空间定义了 struct Student {...};使用 Student me; 时编译器将搜索全局标识符表Student 未找到则在类标识符内搜索。 即表现为可以使用 Student 也可以使用 struct Student如下 // cpp struct Student { int age; };void f( Student me ); // 正确struct 关键字可省略二、若定义了与 Student 同名函数之后则 Student 只代表函数不代表结构体如下 typedef struct Student { int age; } S;void Student() {} // 正确定义后 Student 只代表此函数//void S() {} // 错误符号 S 已经被定义为一个 struct Student 的别名int main() {Student(); struct Student me; // 或者 S me;return 0; }C 中 struct 和 class 总的来说struct 更适合看成是一个数据结构的实现体class 更适合看成是一个对象的实现体。 区别 最本质的一个区别就是默认的访问控制 默认的继承访问权限。struct 是 public 的class 是 private 的。struct 作为数据结构的实现体它默认的数据访问控制是 public 的而 class 作为对象的实现体它默认的成员变量访问控制是 private 的。 union 联合 联合union是一种节省空间的特殊的类一个 union 可以有多个数据成员但是在任意时刻只有一个数据成员可以有值。当某个成员被赋值后其他成员变为未定义状态。联合有如下特点 默认访问控制符为 public可以含有构造函数、析构函数不能含有引用类型的成员不能继承自其他类不能作为基类不能含有虚函数匿名 union 在定义所在作用域可直接访问 union 成员匿名 union 不能包含 protected 成员或 private 成员全局匿名联合必须是静态static的 union 使用 #includeiostreamunion UnionTest {UnionTest() : i(10) {};int i;double d; };static union {int i;double d; };int main() {UnionTest u;union {int i;double d;};std::cout u.i std::endl; // 输出 UnionTest 联合的 10::i 20;std::cout ::i std::endl; // 输出全局静态匿名联合的 20i 30;std::cout i std::endl; // 输出局部匿名联合的 30return 0; }C 实现 C 类 C 实现 C 的面向对象特性封装、继承、多态 封装使用函数指针把属性与方法封装到结构体中继承结构体嵌套多态父类与子类方法的函数指针不同 explicit显式关键字 explicit 修饰构造函数时可以防止隐式转换和复制初始化explicit 修饰转换函数时可以防止隐式转换但 按语境转换 除外 explicit 使用 struct A {A(int) { }operator bool() const { return true; } };struct B {explicit B(int) {}explicit operator bool() const { return true; } };void doA(A a) {}void doB(B b) {}int main() {A a1(1); // OK直接初始化A a2 1; // OK复制初始化A a3{ 1 }; // OK直接列表初始化A a4 { 1 }; // OK复制列表初始化A a5 (A)1; // OK允许 static_cast 的显式转换 doA(1); // OK允许从 int 到 A 的隐式转换if (a1); // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a6(a1); // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a7 a1; // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换bool a8 static_castbool(a1); // OK static_cast 进行直接初始化B b1(1); // OK直接初始化B b2 1; // 错误被 explicit 修饰构造函数的对象不可以复制初始化B b3{ 1 }; // OK直接列表初始化B b4 { 1 }; // 错误被 explicit 修饰构造函数的对象不可以复制列表初始化B b5 (B)1; // OK允许 static_cast 的显式转换doB(1); // 错误被 explicit 修饰构造函数的对象不可以从 int 到 B 的隐式转换if (b1); // OK被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换bool b6(b1); // OK被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换bool b7 b1; // 错误被 explicit 修饰转换函数 B::operator bool() 的对象不可以隐式转换bool b8 static_castbool(b1); // OKstatic_cast 进行直接初始化return 0; }friend 友元类和友元函数 能访问私有成员破坏封装性友元关系不可传递友元关系的单向性友元声明的形式及数量不受限制 using using 声明 一条 using 声明 语句一次只引入命名空间的一个成员。它使得我们可以清楚知道程序中所引用的到底是哪个名字。如 using namespace_name::name;构造函数的 using 声明 在 C11 中派生类能够重用其直接基类定义的构造函数。 class Derived : Base { public:using Base::Base;/* ... */ };如上 using 声明对于基类的每个构造函数编译器都生成一个与之对应形参列表完全相同的派生类构造函数。生成如下类型构造函数 Derived(parms) : Base(args) { }using 指示 using 指示 使得某个特定命名空间中所有名字都可见这样我们就无需再为它们添加任何前缀限定符了。如 using namespace_name name;尽量少使用 using 指示 污染命名空间 一般说来使用 using 命令比使用 using 编译命令更安全这是由于它只导入了指定的名称。如果该名称与局部名称发生冲突编译器将发出指示。using编译命令导入所有的名称包括可能并不需要的名称。如果与局部名称发生冲突则局部名称将覆盖名称空间版本而编译器并不会发出警告。另外名称空间的开放性意味着名称空间的名称可能分散在多个地方这使得难以准确知道添加了哪些名称。 using 使用 尽量少使用 using 指示 using namespace std;应该多使用 using 声明 int x; std::cin x ; std::cout x std::endl; 或者 using std::cin; using std::cout; using std::endl; int x; cin x; cout x endl;:: 范围解析运算符 分类 全局作用域符::name用于类型名称类、类成员、成员函数、变量等前表示作用域为全局命名空间类作用域符class::name用于表示指定类型的作用域范围是具体某个类的命名空间作用域符namespace::name:用于表示指定类型的作用域范围是具体某个命名空间的 :: 使用 int count 11; // 全局::的 countclass A { public:static int count; // 类 A 的 countA::count }; int A::count 21;void fun() {int count 31; // 初始化局部的 count 为 31count 32; // 设置局部的 count 的值为 32 }int main() {::count 12; // 测试 1设置全局的 count 的值为 12A::count 22; // 测试 2设置类 A 的 count 为 22fun(); // 测试 3return 0; }enum 枚举类型 限定作用域的枚举类型 enum class open_modes { input, output, append };不限定作用域的枚举类型 enum color { red, yellow, green }; enum { floatPrec 6, doublePrec 10 };decltype decltype 关键字用于检查实体的声明类型或表达式的类型及值分类。语法 decltype ( expression )decltype 使用 // 尾置返回允许我们在参数列表之后声明返回类型 template typename It auto fcn(It beg, It end) - decltype(*beg) {// 处理序列return *beg; // 返回序列中一个元素的引用 } // 为了使用模板参数成员必须用 typename template typename It auto fcn2(It beg, It end) - typename remove_referencedecltype(*beg)::type {// 处理序列return *beg; // 返回序列中一个元素的拷贝 }引用 左值引用 常规引用一般表示对象的身份。 右值引用 右值引用就是必须绑定到右值一个临时对象、将要销毁的对象的引用一般表示对象的值。 右值引用可实现转移语义Move Sementics和精确传递Perfect Forwarding它的主要目的有两个方面 消除两个对象交互时不必要的对象拷贝节省运算存储资源提高效率。能够更简洁明确地定义泛型函数。 引用折叠 X 、X 、X 可折叠成 XX 可折叠成 X 宏 宏定义可以实现类似于函数的功能但是它终归不是函数而宏定义中括弧中的“参数”也不是真的参数在宏展开的时候对 “参数” 进行的是一对一的替换。 成员初始化列表 好处 更高效少了一次调用默认构造函数的过程。有些场合必须要用初始化列表 常量成员因为常量只能初始化不能赋值所以必须放在初始化列表里面引用类型引用必须在定义的时候初始化并且不能重新赋值所以也要写在初始化列表里面没有默认构造函数的类类型因为使用初始化列表可以不必调用默认构造函数来初始化 initializer_list 列表初始化 用花括号初始化器列表初始化一个对象其中对应构造函数接受一个 std::initializer_list 参数. initializer_list 使用 #include iostream #include vector #include initializer_listtemplate class T struct S {std::vectorT v;S(std::initializer_listT l) : v(l) {std::cout constructed with a l.size() -element list\n;}void append(std::initializer_listT l) {v.insert(v.end(), l.begin(), l.end());}std::pairconst T*, std::size_t c_arr() const {return {v[0], v.size()}; // 在 return 语句中复制列表初始化// 这不使用 std::initializer_list} };template typename T void templated_fn(T) {}int main() {Sint s {1, 2, 3, 4, 5}; // 复制初始化s.append({6, 7, 8}); // 函数调用中的列表初始化std::cout The vector size is now s.c_arr().second ints:\n;for (auto n : s.v)std::cout n ;std::cout \n;std::cout Range-for over brace-init-list: \n;for (int x : {-1, -2, -3}) // auto 的规则令此带范围 for 工作std::cout x ;std::cout \n;auto al {10, 11, 12}; // auto 的特殊规则std::cout The list bound to auto has size() al.size() \n;// templated_fn({1, 2, 3}); // 编译错误“ {1, 2, 3} ”不是表达式// 它无类型故 T 无法推导templated_fnstd::initializer_listint({1, 2, 3}); // OKtemplated_fnstd::vectorint({1, 2, 3}); // 也 OK }面向对象 面向对象程序设计Object-oriented programmingOOP是种具有对象概念的程序编程典范同时也是一种程序开发的抽象方针。 面向对象三大特征 —— 封装、继承、多态 封装 把客观事物封装成抽象的类并且类可以把自己的数据和方法只让可信的类或者对象操作对不可信的进行信息隐藏。关键字public, protected, private。不写默认为 private。 public 成员可以被任意实体访问protected 成员只允许被子类及本类的成员函数访问private 成员只允许被本类的成员函数、友元类或友元函数访问 继承 基类父类—— 派生类子类 多态 多态即多种状态形态。简单来说我们可以将多态定义为消息以多种形式显示的能力。多态是以封装和继承为基础的。C 多态分类及实现 重载多态Ad-hoc Polymorphism编译期函数重载、运算符重载子类型多态Subtype Polymorphism运行期虚函数参数多态性Parametric Polymorphism编译期类模板、函数模板强制多态Coercion Polymorphism编译期/运行期基本类型转换、自定义类型转换 静态多态编译期/早绑定 函数重载 class A { public:void do(int a);void do(int a, int b); };动态多态运行期期/晚绑定 虚函数用 virtual 修饰成员函数使其成为虚函数动态绑定当使用基类的引用或指针调用一个虚函数时将发生动态绑定 注意 可以将派生类的对象赋值给基类的指针或引用反之不可普通函数非类成员函数不能是虚函数静态函数static不能是虚函数构造函数不能是虚函数因为在调用构造函数时虚表指针并没有在对象的内存空间中必须要构造函数调用完成后才会形成虚表指针内联函数不能是表现多态性时的虚函数解释见虚函数virtual可以是内联函数inline吗 动态多态使用 class Shape // 形状类 { public:virtual double calcArea(){...}virtual ~Shape(); }; class Circle : public Shape // 圆形类 { public:virtual double calcArea();... }; class Rect : public Shape // 矩形类 { public:virtual double calcArea();... }; int main() {Shape * shape1 new Circle(4.0);Shape * shape2 new Rect(5.0, 6.0);shape1-calcArea(); // 调用圆形类里面的方法shape2-calcArea(); // 调用矩形类里面的方法delete shape1;shape1 nullptr;delete shape2;shape2 nullptr;return 0; }虚析构函数 虚析构函数是为了解决基类的指针指向派生类对象并用基类的指针删除派生类对象。 虚析构函数使用 class Shape { public:Shape(); // 构造函数不能是虚函数virtual double calcArea();virtual ~Shape(); // 虚析构函数 }; class Circle : public Shape // 圆形类 { public:virtual double calcArea();... }; int main() {Shape * shape1 new Circle(4.0);shape1-calcArea(); delete shape1; // 因为Shape有虚析构函数所以delete释放内存时先调用子类析构函数再调用基类析构函数防止内存泄漏。shape1 NULL;return 0 }纯虚函数 纯虚函数是一种特殊的虚函数在基类中不能对虚函数给出有意义的实现而把它声明为纯虚函数它的实现留给该基类的派生类去做。 virtual int A() 0;虚函数、纯虚函数 类里如果声明了虚函数这个函数是实现的哪怕是空实现它的作用就是为了能让这个函数在它的子类里面可以被覆盖override这样的话编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口是个函数的声明而已它要留到子类里去实现。虚函数在子类里面可以不重写但纯虚函数必须在子类实现才可以实例化子类。虚函数的类用于 “实作继承”继承接口的同时也继承了父类的实现。纯虚函数关注的是接口的统一性实现由子类完成。带纯虚函数的类叫抽象类这种类不能直接生成对象而只有被继承并重写其虚函数后才能使用。抽象类被继承后子类可以继续是抽象类也可以是普通类。虚基类是虚继承中的基类具体见下文虚继承。 虚函数指针、虚函数表 虚函数指针在含有虚函数类的对象中指向虚函数表在运行时确定。虚函数表在程序只读数据段.rodata section见目标文件存储结构存放虚函数指针如果派生类实现了基类的某个虚函数则在虚表中覆盖原本基类的那个虚函数指针在编译时根据类的声明创建。 虚继承 虚继承用于解决多继承条件下的菱形继承问题浪费存储空间、存在二义性。 底层实现原理与编译器相关一般通过虚基类指针和虚基类表实现每个虚继承的子类都有一个虚基类指针占用一个指针的存储空间4字节和虚基类表不占用类对象的存储空间需要强调的是虚基类依旧会在子类里面存在拷贝只是仅仅最多存在一份而已并不是不在子类里面了当虚继承的子类被当做父类继承时虚基类指针也会被继承。 实际上vbptr 指的是虚基类表指针virtual base table pointer该指针指向了一个虚基类表virtual table虚表中记录了虚基类与本类的偏移地址通过偏移地址这样就找到了虚基类成员而虚继承也不用像普通多继承那样维持着公共基类虚基类的两份同样的拷贝节省了存储空间。 虚继承、虚函数 相同之处都利用了虚指针均占用类的存储空间和虚表均不占用类的存储空间不同之处 虚继承 虚基类依旧存在继承类中只占用存储空间虚基类表存储的是虚基类相对直接继承类的偏移 虚函数 虚函数不占用存储空间虚函数表存储的是虚函数地址 类模板、成员模板、虚函数 类模板中可以使用虚函数一个类无论是普通类还是类模板的成员模板本身是模板的成员函数不能是虚函数 抽象类、接口类、聚合类 抽象类含有纯虚函数的类接口类仅含有纯虚函数的抽象类聚合类用户可以直接访问其成员并且具有特殊的初始化语法形式。满足如下特点 所有成员都是 public没有定义任何构造函数没有类内初始化没有基类也没有 virtual 函数 内存分配和管理 malloc、calloc、realloc、alloca malloc申请指定字节数的内存。申请到的内存中的初始值不确定。calloc为指定长度的对象分配能容纳其指定个数的内存。申请到的内存的每一位bit都初始化为 0。realloc更改以前分配的内存长度增加或减少。当增加长度时可能需将以前分配区的内容移到另一个足够大的区域而新增区域内的初始值则不确定。alloca在栈上申请内存。程序在出栈的时候会自动释放内存。但是需要注意的是alloca 不具可移植性, 而且在没有传统堆栈的机器上很难实现。alloca 不宜使用在必须广泛移植的程序中。C99 中支持变长数组 (VLA)可以用来替代 alloca。 malloc、free 用于分配、释放内存 malloc、free 使用 申请内存确认是否申请成功 char *str (char*) malloc(100); assert(str ! nullptr);释放内存后指针置空 free(p); p nullptr;new、delete new / new[]完成两件事先底层调用 malloc 分配了内存然后调用构造函数创建对象。delete/delete[]也完成两件事先调用析构函数清理资源然后底层调用 free 释放空间。new 在申请内存时会自动计算所需字节数而 malloc 则需我们自己输入申请内存空间的字节数。 new、delete 使用 申请内存确认是否申请成功 int main() {T* t new T(); // 先内存分配 再构造函数delete t; // 先析构函数再内存释放return 0; }定位 new 定位 newplacement new允许我们向 new 传递额外的地址参数从而在预先指定的内存区域创建对象。 new (place_address) type new (place_address) type (initializers) new (place_address) type [size] new (place_address) type [size] { braced initializer list }place_address 是个指针initializers 提供一个可能为空的以逗号分隔的初始值列表 delete this 合法吗 合法但 必须保证 this 对象是通过 new不是 new[]、不是 placement new、不是栈上、不是全局、不是其他对象成员分配的必须保证调用 delete this 的成员函数是最后一个调用 this 的成员函数必须保证成员函数的 delete this 后面没有调用 this 了必须保证 delete this 后没有人使用了 如何定义一个只能在堆上栈上生成对象的类 只能在堆上 方法将析构函数设置为私有 原因C 是静态绑定语言编译器管理栈上对象的生命周期编译器在为类对象分配栈空间时会先检查类的析构函数的访问性。若析构函数不可访问则不能在栈上创建对象。 只能在栈上 方法将 new 和 delete 重载为私有 原因在堆上生成对象使用 new 关键词操作其过程分为两阶段第一阶段使用 new 在堆上寻找可用内存分配给对象第二阶段调用构造函数生成对象。将 new 操作设置为私有那么第一阶段就无法完成就不能够在堆上生成对象。 智能指针 C 标准库STL中 头文件#include memory C 98 std::auto_ptrstd::string ps (new std::string(str)) C 11 shared_ptrunique_ptrweak_ptrauto_ptr被 C11 弃用 Class shared_ptr 实现共享式拥有shared ownership概念。多个智能指针指向相同对象该对象和其相关资源会在 “最后一个 reference 被销毁” 时被释放。为了在结构较复杂的情景中执行上述工作标准库提供 weak_ptr、bad_weak_ptr 和 enable_shared_from_this 等辅助类。Class unique_ptr 实现独占式拥有exclusive ownership或严格拥有strict ownership概念保证同一时间内只有一个智能指针可以指向该对象。你可以移交拥有权。它对于避免内存泄漏resource leak——如 new 后忘记 delete ——特别有用。 shared_ptr 多个智能指针可以共享同一个对象对象的最末一个拥有着有责任销毁对象并清理与该对象相关的所有资源。 支持定制型删除器custom deleter可防范 Cross-DLL 问题对象在动态链接库DLL中被 new 创建却在另一个 DLL 内被 delete 销毁、自动解除互斥锁 weak_ptr weak_ptr 允许你共享但不拥有某对象一旦最末一个拥有该对象的智能指针失去了所有权任何 weak_ptr 都会自动成空empty。因此在 default 和 copy 构造函数之外weak_ptr 只提供 “接受一个 shared_ptr” 的构造函数。 可打破环状引用cycles of references两个其实已经没有被使用的对象彼此互指使之看似还在 “被使用” 的状态的问题。 unique_ptr unique_ptr 是 C11 才开始提供的类型是一种在异常时可以帮助避免资源泄漏的智能指针。采用独占式拥有意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer 拥有。一旦拥有着被销毁或编程 empty或开始拥有另一个对象先前拥有的那个对象就会被销毁其任何相应资源亦会被释放。 unique_ptr 用于取代 auto_ptr auto_ptr 被 c11 弃用原因是缺乏语言特性如 “针对构造和赋值” 的 std::move 语义以及其他瑕疵。 auto_ptr 与 unique_ptr 比较 auto_ptr 可以赋值拷贝复制拷贝后所有权转移unqiue_ptr 无拷贝赋值语义但实现了move 语义auto_ptr 对象不能管理数组析构调用 deleteunique_ptr 可以管理数组析构调用 delete[] 强制类型转换运算符 static_cast 用于非多态类型的转换不执行运行时类型检查转换安全性不如 dynamic_cast通常用于转换数值数据类型如 float - int可以在整个类层次结构中移动指针子类转化为父类安全向上转换父类转化为子类不安全因为子类可能有不在父类的字段或方法 dynamic_cast 用于多态类型的转换执行行运行时类型检查只适用于指针或引用对不明确的指针的转换将失败返回 nullptr但不引发异常可以在整个类层次结构中移动指针包括向上转换、向下转换 const_cast 用于删除 const、volatile 和 __unaligned 特性如将 const int 类型转换为 int 类型 reinterpret_cast 用于位的简单重新解释滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的否则应使用其他强制转换运算符之一。允许将任何指针转换为任何其他指针类型如 char* 到 int* 或 One_class* 到 Unrelated_class* 之类的转换但其本身并不安全也允许将任何整数类型转换为任何指针类型以及反向转换。reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。reinterpret_cast 的一个实际用途是在哈希函数中即通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。 bad_cast 由于强制转换为引用类型失败dynamic_cast 运算符引发 bad_cast 异常。 bad_cast 使用 try { Circle ref_circle dynamic_castCircle(ref_shape); } catch (bad_cast b) { cout Caught: b.what(); }运行时类型信息 (RTTI) dynamic_cast 用于多态类型的转换 typeid typeid 运算符允许在运行时确定对象的类型type_id 返回一个 type_info 对象的引用如果想通过基类的指针获得派生类的数据类型基类必须带有虚函数只能获取对象的实际类型 type_info type_info 类描述编译器在程序中生成的类型信息。 此类的对象可以有效存储指向类型的名称的指针。 type_info 类还可存储适合比较两个类型是否相等或比较其排列顺序的编码值。 类型的编码规则和排列顺序是未指定的并且可能因程序而异。头文件typeinfo typeid、type_info 使用 #include iostream using namespace std;class Flyable // 能飞的 { public:virtual void takeoff() 0; // 起飞virtual void land() 0; // 降落 }; class Bird : public Flyable // 鸟 { public:void foraging() {...} // 觅食virtual void takeoff() {...}virtual void land() {...}virtual ~Bird(){} }; class Plane : public Flyable // 飞机 { public:void carry() {...} // 运输virtual void takeoff() {...}virtual void land() {...} };class type_info { public:const char* name() const;bool operator (const type_info rhs) const;bool operator ! (const type_info rhs) const;int before(const type_info rhs) const;virtual ~type_info(); private:... };void doSomething(Flyable *obj) // 做些事情 {obj-takeoff();cout typeid(*obj).name() endl; // 输出传入对象类型class Bird or class Planeif(typeid(*obj) typeid(Bird)) // 判断对象类型{Bird *bird dynamic_castBird *(obj); // 对象转化bird-foraging();}obj-land(); }int main(){Bird *b new Bird();doSomething(b);delete b;b nullptr;return 0; }本文出处
http://www.dnsts.com.cn/news/135811.html

相关文章:

  • 承德市网站建设好看的网站排版
  • 长沙官网网站制作公司网页传奇176
  • 网站排名易下拉排名大画册设计网站
  • 东莞互联网公司排名苏州百度seo代理
  • 四川建设学网官方网站登录网站群建设规范
  • 深圳制作网站主页有什么网站专做买生活污水设备
  • 石家庄网站建设推广公司莱芜拉呱
  • 常州承接网站建设wordpress 仪表板主题
  • 做百度翻译英文网站新闻发布网站建设实训
  • 网站制作aqq泰州网站建设优化
  • 南皮县网站建设价格网站开发一定要用框架嘛
  • 智慧城市网站 seo 优化建议
  • 设计师需要了解的网站做网站实名认证总是失败怎么回事
  • 台州市住房和城乡建设局网站网上推广平台 怎么入手
  • 西安企业网站主题 wordpress
  • 自建房外观设计网站推荐注册工作室流程及费用
  • 重庆微信开发网站建设北京短视频拍摄
  • 怎么做一个电商网站吗网站设计怎么设计学生作业
  • 情人节给女朋友做网站建筑工程施工合同范本
  • 网站系统有哪些python 做网站 数据库
  • 济南网站制作哪家最好做ppt的图片素材网站有哪些
  • 网站建设交流成都做小程序的公司
  • 南昌网站设计企业自己如何建一个网站
  • 做 视频在线观看网站内推网
  • 网站支持asp创意产品设计大赛
  • 网站建设图片上传网络营销的具体措施
  • 国内优秀设计网站wordpress 自定义feed
  • 如何查看网站备案号互联网公司排名去哪里看
  • 国内十大网站建设公司排名广州互联网公司排行榜
  • 如何整合网站天宁网站建设