爱护小动物,享受宠物伙伴

您现在的位置是:首页 > 科技IT > 正文

科技IT

万字长文【C++】高质量编程指南

admin2023-09-21科技IT4689
蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 济南人才网_济南招聘网_济南人才网最新招聘信息_济南人才招聘网 山西人才网_山西招聘网_山西招聘会_山西招聘_山西找工作_最新招聘信息_山西人才市场_山西人才招聘信息_山西人才网 汕头人才网_汕头招聘网_汕头招聘会_汕头招聘_汕头找工作_最新招聘信息_汕头人才市场_汕头人才招聘信息_汕头人才网 赤壁美食网_赤壁美食平台_赤壁特色美食商城门户网 四平招聘网_四平人才网_四平新区人才网_汇聚四平最新招聘信息 六安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 上海招聘网_上海人才网_上海人才市场_上海求职【官方网站】 长春招聘网_长春人才网_长春新区人才网_汇聚长春最新招聘信息 人才招聘网_招聘网_中国人才网 - 求职找工作就上乌鲁木齐人才网 雁塔房产中介_雁塔租房_雁塔找房 六安废品回收-六安二手物资回收-六安电子产品回收-六安废旧金属回收-六安物资回收_六安废品回收网 乌鲁木齐招聘网_乌鲁木齐人才网_乌鲁木齐人才市场_乌鲁木齐求职【官方网站】 新疆招聘_新疆人才网_新疆人才市场-新疆招聘网【新疆聘网】 人才网-招聘网-招聘-招聘信息-最新招聘-求职-找工作-上西安招聘网 赤峰旅游_赤峰旅游攻略_赤峰旅游景点_赤峰旅游网 广州招聘网_广州人才网_广州人才市场_广州求职【官方网站】 蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 西安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 鸡西人才网 鸡西人才市场 最新招聘信息网,找工作求职 东莞招聘网_东莞人才网_东莞人才市场_东莞求职【官方网站】 阳江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 潜江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 招聘网_人才网_找工作_求职_惠州招聘网_精英人才发展平台 青海人才网 - 青海招聘网 - 找好工作上青海招聘网 北海人才网_北海招聘网_北海招聘会_北海招聘_北海找工作_最新招聘信息_北海人才市场_北海人才招聘信息_北海人才网 乌鲁木齐人才网 乌鲁木齐招聘网 乌鲁木齐本地求职招聘平台 海口人才网 - 海口招聘网 - 找好工作上海口招聘网 东莞招聘网-东莞招聘网-东莞人才网,东莞最新招聘信息,东莞人才市场,东莞招聘网,东莞市人才网,东莞找工作 桂林美食网_桂林美食平台_桂林特色美食商城门户网 周口招聘网_周口人才网_周口招聘信息网站 北海招聘网-北海招聘网-北海人才网,北海最新招聘信息,北海人才市场,北海招聘网,北海市人才网,北海找工作 襄阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 湛江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 人才招聘网_招聘网_中国人才网 - 求职找工作就上长沙人才网 南阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 齐齐哈尔招聘网_齐齐哈尔人才网_齐齐哈尔人才市场_齐齐哈尔求职【官方网站】 沈阳人才网招聘信息 淮安人才网 - 淮安招聘网 - 找好工作上淮安招聘网 青海招聘网_青海人才网_青海人才市场_青海求职【官方网站】 三亚人才网_三亚招聘网_三亚人才网最新招聘信息_三亚人才招聘网 本溪迎客松货源-造型油松批发-盆景松价格-本溪景观松基地 苏州看房网_苏州房产中介_苏州找房 三亚人才网_三亚招聘网_三亚招聘会_三亚招聘_三亚找工作_最新招聘信息_三亚人才市场_三亚人才招聘信息_三亚人才网 招聘网_人才网_找工作_求职_海口招聘网_精英人才发展平台 盐城家政 杭州招聘网_杭州人才网_杭州人才市场_杭州求职【官方网站】 沈阳旅游_沈阳旅游攻略_沈阳旅游景点_沈阳旅游网

点击这里持续更新~

8.高质量编程!

8.1.基础知识

1,应用 ifndef/define/endif结构产生预处理块的目的是:防止头文件被重复引用。

2,头文件中只存放声明,而不存放定义,注意:C++语法中,类的成员函数可以再声明的同时被定义,并且自动成为内联函数,这虽然会带来书写上的方便,但却造成了风格不一致,建议将成员函数的定义与声明分开,不论该函数体有多么小。

3,不提倡使用全局变量,尽量不要再头文件中出现 exter int value这类声明。

4,一行代码只做一件事情,如只定义一个变量,或只写一条语句。

5,尽可能在定义变量的同时初始化该变量。

6,if语句

(1)不可将布尔变量直接与true,false或者1,0进行比较

根据布尔类型的语义,零值为"假" (false),任何非零值都是“真”(true),true的值究竟是什么并没有统一的标准。

//bool flag if (flag)//真 if (!flag)//假 //不良风格 if (flag == true) if (flag == 0)

(2)应当将整型变量用 == 或 != 直接与 0 比较

//int value if (value == 0) //不良风格 误解是bool if (!value)

(3)不可将浮点变量用 == 或 != 与任何数字比较

无论是float还是double类型的变量,都有精度限制,所以一定要避免将浮点类型变量用 == 与数字比较,应该设法转换成 >= 或 <= 形式

//float x if (x >= erp) //不良风格 if (x == 0.0)

(4)指针变量直接与 NULL比较,而不是与 0比较

尽管NULL的值与0相同,但是两者的意义不同,回答 if (NULL == p) 和 if (p == NULL)的区别?

因为NULL不能被赋值,如果漏写成 NULL = p,编译器会直接报错的,但是 如果漏写成 p = NULL,不会报错,if语句的含义就变味道了!

7,for循环语句

(1)在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU跨切循环层的次数,效率会提高

//低效率 for (int i =0 ; i <100; i++) { for (int j =0 ; j< 5; j++) { sum += a[i][j]; } } //高效率 长循环在内层 for (int i =0 ; i <5; i++) { for (int j =0 ; j< 100; j++) { sum += a[i][j]; } }

(2)如果循环体内存在逻辑判断,并且循次数很大,将逻辑判断移到循环体的外面。,如果在内部,就会多执行很多次逻辑判断,并且破坏了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。

//效率低 for (int i =0; i < N; i++) { if(cond) { DO(); } else { DONothing(); } } //高效率但是不简洁 if (cond) { for (int i =0 ;i < N ; i++) { DO(); } } else { for (int i =0 ;i < N ; i++) { DONothing(); } }

(3)不可再for循环体内修改循环变量,防止 for循环失去控制。

(4)建议for语句的循环控制变量的取值采用 半开闭区间的写法

//半开半闭 for (int i = 0; i < N; i++) //闭区间 不建议 for (int i = 0 ; i <= N -1; i++)

8,goto语句不建议用,当不是禁止用,goto语句至少有一处可显神通,它能从多重循环体中一下跳到外面,不用写很多次 break语句。

{ { { goto error; } } }

9,const常量有数据类型,而#define没有数据类型,编译器可以对前者进行类型安全检查,而只对后者进行字符替换,没有类型安全检查。const常量完全可以取代宏常量。

(1)不能再类声明中初始化 const数据成员,因为类的对象未被创建时,编译器不知道 SIZE的值是多少。

class A { //错误,在类声明中初始化const数据成员 const int SIZE = 100; //错误,未知的SIZE int array[SIZE]; };

(2)const 数据成员的初始化只能在类构造函数的初始化表中进行。

class A { A(int size); const int SIZE; }; A::A(int size):SIZE(size) { } A a(200); A b(100);

(3)通过类中的枚举常量实现在整个类中都恒定的常量,不用指望const数据成员了。

枚举常量不会占用对象的存储空间,它们在编译时被全部求值,其缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

class A { enum{SIZE =100, SIZE2 =200}; int array1[SIZE]; int arrray2[SIZE2]; };

10,函数设计

(1)如果函数没有参数,则用 void填充。

float GetValue(void);//良好风格 float GetValue();//不良风格

(2)目的参数放在前面,源参数放在后面

(3)如果参数是指针,且仅作输入用,则应在类型前加 const,以防止该指针在函数体内被意外修改。

void StringCopy(char *Des, const char *str)

(4)如果输入的参数以值传递的方式传递对象,则改用 const & 方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。

(5)如果函数的返回值是一个对象,有些场合用引用传递替换值传递可以提高效率,而有些场合只能用值传递而不能用引用传递,否则会出错。

class STring { //赋值函数 String & operate==(const STring &other); //相加函数,如果没有 friend修饰只允许有一个右侧参数 friend String operate+(const STring &s1, const String &s2); private: char *m_data; }; //赋值函数的实现 String & String::operate=(const String &other) { if (this == &other) { return *this; } m_Data = new char[strlen(other.data) + 1]; strcpy(m_data, other.data); //返回的是 *this的引用,无需拷贝过程 retrun *this; }

赋值函数,应用引用传递的方式返回String 对象,如果用值传递的方式,虽然功能仍然正确,但由于 retuern 语句要把 *this 拷贝到保存返回值的外部存储单元之中,增加了不必要的开销,降低了赋值函数的效率。

String a,b,c; //如果用值传递,将产生一次 *this的拷贝 a =b; //将产生两次的 *this拷贝 a=b=c;

String 的相加函数 operate++ 的实现如下。

String operate+(const String &s1, const String &s2) { String temp;//值传递 delete temp.data; temp.data = new char[strlen(s1.data) + strlen(s2.data) +1]; strcpy(temp.data,s1.data); strcat(temp.data,s2.data); return temp; }

对于相加函数,应用值传递的方式返回String对象,如果改用 引用传递,那么函数返回值是一个指向局部对象 temp的引用,由于temp在函数结束时被自动销毁,将导致返回的引用无效。

c =a +b;//此时a+b并不返回期望值,c什么也得不到,留下隐患

(6)return语句不可返回指向 栈内存 的指针或者引用,因为该内存在函数体结束时被自动销毁

char *FUN(void) { //str的内存位于栈上 char str[] = “hello" //将导致错误 return str; }

如果函数返回值是一个对象,要考虑return语句的效率。创建一个临时对象并返回它,如下。

return String(s1+s2);

编译器直接把临时对象创建并初始化在外部存储单元中,省去了拷贝和析构的消耗,提高了效率

区别:先创建一个局部对象 temp并返回它的结果

String temp(s1+s2);

return temp;

上述代码将发生三件事:

1,首先temp对象被创建,同时完成初始化

2,然后拷贝构造函数把temp拷贝到保存返回值的外部存储单元中

3,最后,temp在函数结束时被销毁,调用析构函数

类似地:

return int(x+y)

不要写成:

int temp =x+y;

return temp;

由于内部数据类型如 int,float ,double的变量不存在构造函数和析构函数,虽然该临时变量的语法不会提高多少效率,但是程序更加简洁易读。

(7)assert不是函数,而是宏

(8)引用与指针的区别

1,int m; int &n = m

n是m的一个引用,m是被引用物,n相当于m的别名,对n的任何操作就是对m的操作。所以n即不是m的拷贝,也不是指向m的指针,其实n就是m它自己。

2,引用被创建的同时必须被初始化,指针则可以在任何时候被初始化

3,不能有NULL引用,引用必须与合法的存储单元关联,指针则可以是NULL

4, 一旦引用被初始化,就不能改变引用的关系,指针则可以随时改变所指的对象

int i =5; int j =6; int &k = i; k = j;

k和i的值都变成了6。

8.2.内存管理

8.2.1.内存的分配方式

1,静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量

2,在栈上创建:在执行函数时候,函数内部局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

3,堆内存:动态内存分配,程序在运行时候用malloc或new申请任意多少的内存,程序员自己负责在何时用 free或delete释放内存,动态内存的生存期由我们决定,使用灵活,但是问题也多。

8.2.2.内存使用错误

1,内存分配未成功,却使用了它

使用之前检查是否存在,如果是函数入口,可以 assert(p != NULL),如果是malloc或new申请内存,可以 if (NULL == p)进行防错处理

2,内存分配虽然成功,但是尚未初始化就引用它

注意内存的缺省值初值是什么并没有统一标准,不一定全为0,因此,在创建数组时候,别忘记赋初始值,赋0也不能省略。

3,内存分配成功并且已经初始化,但操作越过了内存的边界

数组操作越界

4,忘记了释放内存,造成内存泄漏

含有这种错误的函数每被调用一次就丢失一块内存,刚开始时系统的内存充足,你看不到错误,终有一次程序突然死掉,系统出现提示:内存耗尽

malloc/free,new/delete必须成对出现

5,释放了内存却继续使用它

(1)return语句写错了,注意不要返回指向 栈内存 的指针或者引用,因为该内存在函数体结束时被自动销毁

(2)free或delete释放了内存之后,没有将指针设置为NULL,导致产生了 野指针

8.2.3.指针与数组对比

数组要么在静态存储区被创建,如全局数组,要么在栈上被创建。数组名对应着一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。

指针可以随时指向任意类型的内存块,它的特征是 可变,所以我们常用指针来操作动态内存,指针远比数组灵活,但也更危险。

字符串比较指针与数组

1,修改内容

//字符数组a的容量是 6个字符,内容 hello\0 char a[] = "hello"; //a的内容可以改变 a[0] = X; //指针p指向常量字符串 "world",位于静态存储区,内容是 world\0 char *p = "world"; //常量字符串的内容是不可以被修改的 p[0] = X;//运行时出错,编译器不能发现该错误

2,内容复制与比较

不能对数组名进行直接复制与比较,否则会产生编译错误;

指针 p =a 并不能把 a的内容复制指针 p,而是把 a的地址赋给了p。要想复制 a的内容,可以先用库函数 malloc为p申请一块容量 为 strlen(a) +1个字符的内存,再用strcpy进行字符串复制。

//数组 char a[] = "hello"; char b[10]; //不能 b = a,而是 strcpy(b,a); //不能 b ==a ,而是 if(strcmp(b,a) == 0) //指针 int len =strlen(a) char *p = (char*)malloc(sizeof(char)*(len+1)); //不能 p = a,而是 strcpy(p,a); //不能 p ==a ,而是 if(strcmp(p,a) == 0)

3,计算内存容量

sizeof计算数组的容量(字节数),并忘记 + "\0"。

char a[] = "hello world"; char *p =a; sizeof(a);//12 加\0 sizeof(p);//4 得到的是一个指针变量的字节数,相当于 sizeof(char*),而不是p所指的内存容量 //当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针 void Func(char a[100]) { sizeof(a);//4 而不是100 }

8.2.4.指针参数如何传递内存

1,如果函数的参数是一个指针,不要指望用该指针去申请动态内存。

void GetMemory(char *p ,int num) { p = (char*)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; //str仍然为NULL,没有获的期望的内存 GetMemory(str,100) //运行错误 strcpy(str,"hello"); }

为什么?

编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器 使 _p =p,如果函数体内的程序修改了 _p的内容,就导致参数p的内容作相应的修改,这就是指针可以作为输出参数的原因。本例中,__p申请了新的内存,只是把 —p所指的内存地址改变了,但是p丝毫没变,所以该函数并不能输出任何东西。相反,每调用一次,就好泄漏一块内存,因为没有free释放。

2,可以用 指向指针的指针 实现用指针参数去申请内存

void GetMemory(char **p ,int num) { *p = (char*)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; //&str GetMemory(&str,100) //运行错误 strcpy(str,"hello"); cout<<str<<endl; free(str); }

3,继续简化为函数返回值来传递动态内存

char *GetMemory(int num) { p = (char*)malloc(sizeof(char) * num); return p; } void Test(void) { char *str = NULL; str = GetMemory(100); //运行错误 strcpy(str,"hello"); free(str); }

4,不要用 return语句返回指向 栈内存的指针,因为该内存在函数结束时自动消亡

char *GetMemory(int num) { char p[] = "hello world"; return p;//编译器将提出警告 } void Test(void) { char *str = NULL; str = GetMemory();//str的内容是垃圾,不是NULL //运行错误 strcpy(str,"hello"); free(str); }

8.2.5.free和delete把指针怎么了

它们只是把指针所指的内存给释放掉,当并没有把指针本身干掉。

char *p =(char*)malloc(100); strcpy(p,”hello); //p所指向的内存被释放,但是p所指的地址仍然不变 //不是NULL,只是该地址对应的内存是垃圾,p成了野指针 free(p); ..... if(p != NULL)//没有起到防错作用 { //野指针,出错 strcpy(p,"hello"); }

8.2.6.杜绝野指针

野指针不是NULL指针,是指向 垃圾内存的指针,野指针很危险,if拦不住,成为野指针的原因有:

1,指针变量没有被初始化

指针变量在创建的同时应当被初始化,要么将指针设置为 NULL,要么让它指向合法的内存。

char *p = NULL: cahr *str = (char*)malloc(100);

2,指针 p被free或者delete之后,没有设为NULL

3,指针操作超越了变量的作用范围

class A { public: void Func(void){ cout << “Func of class A” << endl; } }; void Test(void) { A *p; { A a; p = &a; // 注意 a 的生命期 } //对象a已经消失,p指向a,所以p成了野指针 p->Func(); // p 是“野指针” }

8.2.7.malloc/free和new/delete的区别

malloc/free是 C++/C语言标准的库函数,对于非内部数据类型的对象而言,它无法满足动态对象的要求,对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数,库函数不在编译器控制的权限之内,不能执行构造和析构。

new/delete是C++运算符,能完成动态内存分配和初始化工作,如何实现动态内存管理。

class Obj { public : Obj(void){ cout << “Initialization” << endl; } ~Obj(void){ cout << “Destroy” << endl; } void Initialize(void){ cout << “Initialization” << endl; } void Destroy(void){ cout << “Destroy” << endl; } }; //malloc/free不能执行构造函数和析构函数,必须调用成员函数来完成初始化和清除工作 void UseMallocFree(void) { Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存 a->Initialize(); // 初始化 //… a->Destroy(); // 清除工作 free(a); // 释放内存 } //new/delete本身就可以完成构造和析构 void UseNewDelete(void) { Obj *a = new Obj; // 申请动态内存并且初始化 //… delete a; // 清除并且释放内存 }

如果用 free释放 new创建的动态对象,那么该对象因无法执行析构函数而可能导致程序出错

如果用delete释放malloc申请的动态内存,理论上程序不会出错,但是可读性差,因此,必须成对出现。

8.3.函数的高级特性

重载 overloaded,内联 inline: 既可以用于全局函数也可用于类的成员函数;

const和virtual仅仅用于类的成员函数。

8.3.1.重载

语义,功能相似的几个函数用同一个名字表示,提高函数的易用性。并且,类的构造函数需要重载,C++规定构造函数于类同名,只有一个名字,如果想用几种不同的方法创建对象,只能用重载机制来实现,所以类可以有多个同名的构造函数。

辨识重载:靠参数而不是返回值的不同来区分重载函数,编译器根据参数为每个重载函数产生不同的内部标识符号。

extern "C"的用处

如果C++程序要调用已经被编译后的C函数,我?

假设谋个 C函数的声明如下: void foo(int x,int y)

//该函数被C编译器编译后在库中的名字为 _foo,而C++编译器则会产生像 _foo_int_int之类的名字用来支持函数重载和类型检查 //由于编译后的名字不同,C++程序不能直接调用C函数,因此,c++提高了一个C连接交换指定符合 extern “C”来解决这个问题。 extern “C” { void foo(int x, int y); ⋯ // 其它函数 } 或者写成 extern “C” { #include “myheader.h” ⋯ // 其它C 头文件 }

注意并不是两个函数的名字相同就能构成重载,全局函数和类的成员函数同名不算重载,因为函数的作用域不同。例如

void Print(⋯); // 全局函数 class A {⋯ void Print(⋯); // 成员函数 } //全局函数的调用 ::Print(i)

8.3.2.覆盖

成员函数被重载:

1,相同的范围,在同一个类中

2,函数名字相同

3,参数不同

4,virtual关键字可有可恶

覆盖指派生类函数覆盖基类函数

1,不同的范围

2,函数名字相同

3,参数相同

4,基类必须有关键字 virtual

class Base { public: void f(int x){ cout << "Base::f(int) " << x << endl; } void f(float x){ cout << "Base::f(float) " << x << endl; } virtual void g(void){ cout << "Base::g(void)" << endl;} }; class Derived : public Base { public: virtual void g(void){ cout << "Derived::g(void)" << endl;} }; void main(void) { Derived d; Base *pb = &d; pb->f(42); // Base::f(int) 42 pb->f(3.14f); // Base::f(float) 3.14 pb->g(); // Derived::g(void) }

8.3.3.隐藏

派生类的函数屏蔽了与其同名的基类函数

1,如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有没virtual,基类函数将被隐藏:区别重载

2,如果派生类函数与基类的函数同名,并且参数也显然,但是基类没有virtual关键字,此时,基类函数被隐藏;区别覆盖

class Base { public: virtual void f(float x){ cout << "Base::f(float) " << x << endl; } void g(float x){ cout << "Base::g(float) " << x << endl; } void h(float x){ cout << "Base::h(float) " << x << endl; } }; class Derived : public Base { public: //覆盖了基类f(float) virtual void f(float x){ cout << "Derived::f(float) " << x << endl; } //隐藏了基类g(float) void g(int x){ cout << "Derived::g(int) " << x << endl; } //隐藏了基类h(float) void h(float x){ cout << "Derived::h(float) " << x << endl; } }; //测试 void main(void) { Derived d; Base *pb = &d; Derived *pd = &d; // Good : behavior depends solely on type of the object pb->f(3.14f); // Derived::f(float) 3.14 pd->f(3.14f); // Derived::f(float) 3.14 // Bad : behavior depends on type of the pointer //隐藏依赖指针类型 pb->g(3.14f); // Base::g(float) 3.14 pd->g(3.14f); // Derived::g(int) 3 (surprise!) // Bad : behavior depends on type of the pointer pb->h(3.14f); // Base::h(float) 3.14 (surprise!) pd->h(3.14f); // Derived::h(float) 3.14 }

隐藏带来的麻烦和改造

class Base { public: void f(int x); }; class Derived : public Base { public: void f(char *str); }; void Test(void) { Derived *pd = new Derived; pd->f(10); // error } //改造 class Derived : public Base { public: void f(char *str); void f(int x) { Base::f(x); } };

8.3.4.参数的缺省值

有一些参数在每次函数调用时都相同,因此用缺省值变得简洁。

1,参数缺省值只能出现在函数的声明中,而不能出现在定义体内

void Foo(int x=0, int y=0); // 正确,缺省值出现在函数的声明中 void Foo(int x=0, int y=0) // 错误,缺省值出现在函数的定义体中 { ⋯ }

为什么?一是函数的定义本来就与参数是否有缺省值无关,所以没有必要让缺省值出现在函数的定义体内;二是参数的缺省值可能还会改动,显然修改函数的声明比修改函数的定义要方便。

2,如果函数有多个参数,参数只能从后向前挨个缺省

正确的示例如下: void Foo(int x, int y=0, int z=0); 错误的示例如下: void Foo(int x=0, int y, int z=0);

8.3.5.运算符重载

关键字 operator加上运算符来表示函数。

Complex operator +(const Complex &a, const Complex &b);

8.3.6.函数内联

inline,目的是提高函数的执行效率。

C程序中,可以用宏代码提高执行效率,宏代码本身不是函数,但使用起来像函数,预处理器用复制宏代码的方式替代函数调用,省去了参数压栈,生成汇编语言的CALL调用,返回参数,执行return等过程,从而提高了速度。

C++的函数内联是如何工作的?

内联函数,编译器在符号表里放入函数的声明,包括名字,参数类型和返回值类型,如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里,在调用一个内联函数时,编译器首先检查调用是否正确,进行类型安全检查,或者进行自动类型转换,如果正确,内联函数的代码就会直接替换函数的调用,于是省去了函数调用的开销。假设内联函数 是成员函数,对象的地址 this会被放在合适的地方,这是预处理器办不到的。

与预处理不同?

预处理器不能进行类型安全检查,或者进行自动类型转换。

1,关键字inline必须与函数定义体放在一起才能使函数成为内联,仅与声明一起不起作用

inline void Foo(int x, int y); // inline 仅与函数声明放在一起 void Foo(int x, int y) { ⋯ } //才是内联 void Foo(int x, int y); inline void Foo(int x, int y) // inline 与函数定义体放在一起 { ⋯ }

2,定义在类声明之中的成员函数将自动地成为内联函数

class A { public: void Foo(int x, int y) { ⋯ } // 自动地成为内联函数 } //但以上不是良好编程风格,改为 // 头文件 class A { public: void Foo(int x, int y); } // 定义文件 inline void A::Foo(int x, int y) { ⋯ }

慎用内联

1,内联是以代码膨胀复制为代价,仅仅省去了函数调用地开销,但是如果函数体内执行代码时间相比于函数调用开销大,将没有收益

2,函数体内的代码比较长,使用内联将导致内存消耗代价较高

3,函数体内出现循环,那么执行函数体内代码的时间要比函数调用开销大

4,不要随便地将构造函数和析构函数的定义体放在类声明中,默认为inline。

8.4.类的设计

8.4.1.构造函数析构函数与赋值函数

每个类只有一个析构函数和一个赋值函数,但是可以有多个构造函数,包含一个拷贝构造函数,其他的成为普通构造函数。

对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省的函数。

A(void); // 缺省的无参数构造函数 A(const A &a); // 缺省的拷贝构造函数 位拷贝 ~A(void); // 缺省的析构函数 A & operate =(const A &a); // 缺省的赋值函数 值拷贝 class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &other); // 拷贝构造函数 ~ String(void); // 析构函数 String & operate =(const String &other); // 赋值函数 private: char *m_data; // 用于保存字符串 };

为什么会有拷贝和析构函数?

根据经验,不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成,因此把对象的初始化放在构造函数,把清除工作放在析构函数,当对象被创建时候,构造自动执行,对象消亡时,析构自动执行,不要担心忘记对象的初始化和清除工作了。

8.4.2.构造函数的初始化列表

初始化列表工作发生在函数体内的任何代码被执行之前

1,如果类存在继承关系,派生类必须在其初始化列表里调用基类的构造函数

class A {… A(int x); // A 的构造函数 }; class B : public A {… B(int x, int y);// B 的构造函数 }; B::B(int x, int y) : A(x) // 在初始化表里调用A 的构造函数 { … }

2,类的const常量只能在初始化列表里被初始化,因为它不能在函数体内赋值的方式来初始化

3,非内部数据类型的成员对象应当采用初始化列表方式来初始化,以获取更高的效率。

class A {… A(void); // 无参数构造函数 A(const A &other); // 拷贝构造函数 A & operate =( const A &other); // 赋值函数 }; class B { public: B(const A &a); // B 的构造函数 private: A m_a; // 成员对象 }; //初始化列表 B::B(const A &a) : m_a(a) { … } //函数体内赋值 //先暗地里创建 m_a对象,调用A的无参数构造函数,再调用A的赋值函数,将参数a赋给m_a B::B(const A &a) { m_a = a; … }

注意:成员对象初始化的次序完全不受他们再初始化表中的次序的影响,只由成员对象在类中声明的次序决定,因为类的声明是唯一的,而类的构造函数可以有多个,因此会有不同次序的初始化表。如果成员对象按照初始化表的次序进行构造,将导致析构函数无法得到唯一的逆序。

8.4.3.分析String的构造与析构

1,string的普通构造

// String 的普通构造函数 String::String(const char *str) { if(str==NULL) { m_data = new char[1]; *m_data = ‘\0’; } else { int length = strlen(str); m_data = new char[length+1]; strcpy(m_data, str); } } // String 的析构函数 String::~String(void) { delete [] m_data; // 由于m_data 是内部数据类型,也可以写成 delete m_data; }

2,string的拷贝构造

// 拷贝构造函数 String::String(const String &other) { // 允许操作other 的私有成员m_data int length = strlen(other.m_data); m_data = new char[length+1]; strcpy(m_data, other.m_data); } // 赋值函数 String & String::operate =(const String &other) { // (1) 检查自赋值 if(this == &other) return *this; // (2) 释放原有的内存资源,不释放会造成内存泄漏 delete [] m_data; // (3)分配新的内存资源,并复制内容 int length = strlen(other.m_data); m_data = new char[length+1]; strcpy(m_data, other.m_data); // (4)返回本对象的引用 return *this; }

引用不可能为NULL,但是指针可以为NULL,不能 return other,因为可能other是个临时对象,在赋值结束后它马上消失,那么return other返回的将是垃圾。

8.4.4.派生类中实现类的基本函数

1,派生类的构造函数应在其初始化列表调用基类的构造函数

2,基类与派生类的析构函数应该设置virtual

class Base { public: virtual ~Base() { cout<< "~Base" << endl ; } }; class Derived : public Base { public: virtual ~Derived() { cout<< "~Derived" << endl ; } }; void main(void) { Base * pB = new Derived; // upcast delete pB; }

输出结果为: ~Derived ~Base 如果析构函数不为虚,那么输出结果为 ~Base

3,在编写派生类的赋值函数时,注意不要忘记对基类的数据成员进行重新赋值

class Base { public: … Base & operate =(const Base &other); // 类Base 的赋值函数 private: int m_i, m_j, m_k; }; class Derived : public Base { public: … Derived & operate =(const Derived &other); // 类Derived 的赋值函数 private: int m_x, m_y, m_z; }; Derived & Derived::operate =(const Derived &other) { //(1)检查自赋值 if(this == &other) return *this; //(2)对基类的数据成员重新赋值 Base::operate =(other); // 因为不能直接操作私有数据成员 //(3)对派生类的数据成员赋值 m_x = other.m_x; m_y = other.m_y; m_z = other.m_z; //(4)返回本对象的引用 return *this; }

8.4.4.const成员函数

const更大的魅力是它可以修饰函数的参数,返回值,甚至函数的定义体。

函数参数:

1,如果输入参数采用指针传递,那么加 const防止意外改动该指针,起到保护作用

void StringCopy(char *strDestination, const char *strSource);

2,如果采用值传递,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,不要加const

3,对于非内部数据类型的参数,void Func(A a)这样声明的函数注定效率比价低,因为函数体内将产生A类型的临时对象用来复制参数a,而临时对象的构造、复制,析构都将消耗时间。 void Func(const A &a) 这样仅仅借用一下参数别名,不需要产生临时对象,提高效率。

4,对于内部数据类型没有必要写成 void Func(const int &X),因为内部数据类型参数不存在构造,析构过程

函数返回值

5,如果给以 指针传递方式的函数返回值加 const修饰,那么函数返回值 指针的内容不能被修改,该返回值只能被赋给加 const修饰的同类型指针

例如函数 const char * GetString(void); 如下语句将出现编译错误: char *str = GetString(); 正确的用法是 const char *str = GetString();

6,如果函数返回值采用值传递方式,由于函数会把返回值复制到外部临时的存储单元中,加 const修饰没有任何价值

例如不要把函数int GetInt(void) 写成const int GetInt(void)

7,函数返回值采用引用传递的场合并不多,这样方式一般只出现在类的赋值函数中,目的是为了实现链式传递

class A {⋯ A & operate = (const A &other); // 赋值函数 }; A a, b, c; // a, b, c 为A 的对象 ⋯ a = b = c; // 正常的链式赋值 (a = b) = c; // 不正常的链式赋值,但合法

成员函数

8,任何不会修改数据成员的函数都应该声明为const类型,如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将报错,提高程序的健壮性。

class Stack { public: void Push(int elem); int Pop(void); int GetCount(void) const; // const 成员函数 private: int m_num; int m_data[100]; }; int Stack::GetCount(void) const { ++ m_num; // 编译错误,企图修改数据成员m_num Pop(); // 编译错误,企图调用非const 函数 return m_num; }

蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 济南人才网_济南招聘网_济南人才网最新招聘信息_济南人才招聘网 山西人才网_山西招聘网_山西招聘会_山西招聘_山西找工作_最新招聘信息_山西人才市场_山西人才招聘信息_山西人才网 汕头人才网_汕头招聘网_汕头招聘会_汕头招聘_汕头找工作_最新招聘信息_汕头人才市场_汕头人才招聘信息_汕头人才网 赤壁美食网_赤壁美食平台_赤壁特色美食商城门户网 四平招聘网_四平人才网_四平新区人才网_汇聚四平最新招聘信息 六安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 上海招聘网_上海人才网_上海人才市场_上海求职【官方网站】 长春招聘网_长春人才网_长春新区人才网_汇聚长春最新招聘信息 人才招聘网_招聘网_中国人才网 - 求职找工作就上乌鲁木齐人才网 雁塔房产中介_雁塔租房_雁塔找房 六安废品回收-六安二手物资回收-六安电子产品回收-六安废旧金属回收-六安物资回收_六安废品回收网 乌鲁木齐招聘网_乌鲁木齐人才网_乌鲁木齐人才市场_乌鲁木齐求职【官方网站】 新疆招聘_新疆人才网_新疆人才市场-新疆招聘网【新疆聘网】 人才网-招聘网-招聘-招聘信息-最新招聘-求职-找工作-上西安招聘网 赤峰旅游_赤峰旅游攻略_赤峰旅游景点_赤峰旅游网 广州招聘网_广州人才网_广州人才市场_广州求职【官方网站】 蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 西安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 鸡西人才网 鸡西人才市场 最新招聘信息网,找工作求职 东莞招聘网_东莞人才网_东莞人才市场_东莞求职【官方网站】 阳江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 潜江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 招聘网_人才网_找工作_求职_惠州招聘网_精英人才发展平台 青海人才网 - 青海招聘网 - 找好工作上青海招聘网 北海人才网_北海招聘网_北海招聘会_北海招聘_北海找工作_最新招聘信息_北海人才市场_北海人才招聘信息_北海人才网 乌鲁木齐人才网 乌鲁木齐招聘网 乌鲁木齐本地求职招聘平台 海口人才网 - 海口招聘网 - 找好工作上海口招聘网 东莞招聘网-东莞招聘网-东莞人才网,东莞最新招聘信息,东莞人才市场,东莞招聘网,东莞市人才网,东莞找工作 桂林美食网_桂林美食平台_桂林特色美食商城门户网 周口招聘网_周口人才网_周口招聘信息网站 北海招聘网-北海招聘网-北海人才网,北海最新招聘信息,北海人才市场,北海招聘网,北海市人才网,北海找工作 襄阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 湛江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 人才招聘网_招聘网_中国人才网 - 求职找工作就上长沙人才网 南阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 齐齐哈尔招聘网_齐齐哈尔人才网_齐齐哈尔人才市场_齐齐哈尔求职【官方网站】 沈阳人才网招聘信息 淮安人才网 - 淮安招聘网 - 找好工作上淮安招聘网 青海招聘网_青海人才网_青海人才市场_青海求职【官方网站】 三亚人才网_三亚招聘网_三亚人才网最新招聘信息_三亚人才招聘网 本溪迎客松货源-造型油松批发-盆景松价格-本溪景观松基地 苏州看房网_苏州房产中介_苏州找房 三亚人才网_三亚招聘网_三亚招聘会_三亚招聘_三亚找工作_最新招聘信息_三亚人才市场_三亚人才招聘信息_三亚人才网 招聘网_人才网_找工作_求职_海口招聘网_精英人才发展平台 盐城家政 杭州招聘网_杭州人才网_杭州人才市场_杭州求职【官方网站】 沈阳旅游_沈阳旅游攻略_沈阳旅游景点_沈阳旅游网 宜昌市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 淮北市语乐文学网_都市言情小说在线阅读网站,让您语中作乐! 黄冈市海豹文学网_无弹窗的网络小说阅读网站_海豹文学网 神农架林区海豹文学网_无弹窗的网络小说阅读网站_海豹文学网 许昌市品阅小说网 中山市品阅小说网 武汉市品阅小说网 安庆市语乐文学网_都市言情小说在线阅读网站,让您语中作乐! 三门峡市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 荆州市便民查询网 - 免费查询工具大全 - 原51240便民查询网 神农架林区企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 随州市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 武陵源聚兴步进电机有限公司 通化市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 黄山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 珠海市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 鄂州市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 七台河市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 黄山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 新时代创业利器有限公司 中山市众仕达照明科技有限公司 汕尾市便民查询网 - 免费查询工具大全 - 原51240便民查询网 恩施土家族苗族自治州本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 武汉市便民查询网 - 免费查询工具大全 - 原51240便民查询网 佛山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 优直播官网-官网首页(中国)有限公司 手拉手同业批发中心 网络免费咨询平台-株洲阳光泌尿专科医院 通化市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 漯河市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 淮北市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 济源市便民查询网 - 免费查询工具大全 - 原51240便民查询网 黄石市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 神农架林区便民查询网 - 免费查询工具大全 - 原51240便民查询网 仙桃市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 襄阳市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 十堰市便民查询网 - 免费查询工具大全 - 原51240便民查询网 江门市便民查询网 - 免费查询工具大全 - 原51240便民查询网 呼和浩特市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 济源市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 安庆市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 二三四五【影视大全】_2021影视大全在线观看 汕头市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 濮阳市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 清远市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 安庆市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 咸宁市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 云浮市心愿梦有限公司 - 独一无二的个性定制服务 宿迁市心语泉有限公司 - 展现指尖的时尚与魅力 绍兴市花影梦有限公司 - 共同守护地球家园 荆州市恬淡梦有限公司 - 提升魅力,尽显自信 阜阳市心弯月有限责任公司 - 开启知识的大门,追求成长 中山市花蕊影股份有限公司 - 燃创造力的火花 芜湖市梦幻夜股份公司 - 美好生活,尽在指尖 三门峡市烟雨桃有限公司 - 发现世界,开启冒险 锡林郭勒盟心弦影有限公司 - 宠物天堂,爱心守护 九江市翩跹曲股份公司 - 拥抱文字,享受阅读之乐 嘉兴市琉璃心股份有限公司 - 健康生活,幸福滋养 台州市雨夜诗有限公司 - 旅行体验,留下回忆 扬州市花海梦股份公司 - 财经投资,智慧决策 上海市悠长夜有限责任公司 - 分享快乐,留住美好 郑州市紫罗舞有限公司 - 知识的海洋,永不停歇 佳木斯市温柔风股份有限公司 - 美容秘籍,焕发魅力 衡水市恬淡缘有限责任公司 - 个性时尚,尽显风采 黑河市青山梦有限公司 - 最新数码产品,尽在触手可及 衢州市梦幻境有限公司 - 尽情享受欢乐时光 运城市青山翠有限公司 - 品味美食,尽享味蕾盛宴 东莞市花蕊影股份有限公司 - 发现世界的奇迹 宣城市雪舞风有限公司 - 关注健康,享受生活 邯郸市温润泉股份公司 - 家庭亲子时光的欢乐场所 六安市轻柔韵有限责任公司 - 创业启示,追逐梦想 荆州市温润夜股份公司 - 健康生活,追求幸福 承德市烟雨桃有限责任公司 - 教育培训,成就未来 通辽市恬淡梦有限公司 - 美容秘籍,尽显自信

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~
蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 济南人才网_济南招聘网_济南人才网最新招聘信息_济南人才招聘网 山西人才网_山西招聘网_山西招聘会_山西招聘_山西找工作_最新招聘信息_山西人才市场_山西人才招聘信息_山西人才网 汕头人才网_汕头招聘网_汕头招聘会_汕头招聘_汕头找工作_最新招聘信息_汕头人才市场_汕头人才招聘信息_汕头人才网 赤壁美食网_赤壁美食平台_赤壁特色美食商城门户网 四平招聘网_四平人才网_四平新区人才网_汇聚四平最新招聘信息 六安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 上海招聘网_上海人才网_上海人才市场_上海求职【官方网站】 长春招聘网_长春人才网_长春新区人才网_汇聚长春最新招聘信息 人才招聘网_招聘网_中国人才网 - 求职找工作就上乌鲁木齐人才网 雁塔房产中介_雁塔租房_雁塔找房 六安废品回收-六安二手物资回收-六安电子产品回收-六安废旧金属回收-六安物资回收_六安废品回收网 乌鲁木齐招聘网_乌鲁木齐人才网_乌鲁木齐人才市场_乌鲁木齐求职【官方网站】 新疆招聘_新疆人才网_新疆人才市场-新疆招聘网【新疆聘网】 人才网-招聘网-招聘-招聘信息-最新招聘-求职-找工作-上西安招聘网 赤峰旅游_赤峰旅游攻略_赤峰旅游景点_赤峰旅游网 广州招聘网_广州人才网_广州人才市场_广州求职【官方网站】 蚌埠市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 西安市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 鸡西人才网 鸡西人才市场 最新招聘信息网,找工作求职 东莞招聘网_东莞人才网_东莞人才市场_东莞求职【官方网站】 阳江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 潜江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 招聘网_人才网_找工作_求职_惠州招聘网_精英人才发展平台 青海人才网 - 青海招聘网 - 找好工作上青海招聘网 北海人才网_北海招聘网_北海招聘会_北海招聘_北海找工作_最新招聘信息_北海人才市场_北海人才招聘信息_北海人才网 乌鲁木齐人才网 乌鲁木齐招聘网 乌鲁木齐本地求职招聘平台 海口人才网 - 海口招聘网 - 找好工作上海口招聘网 东莞招聘网-东莞招聘网-东莞人才网,东莞最新招聘信息,东莞人才市场,东莞招聘网,东莞市人才网,东莞找工作 桂林美食网_桂林美食平台_桂林特色美食商城门户网 周口招聘网_周口人才网_周口招聘信息网站 北海招聘网-北海招聘网-北海人才网,北海最新招聘信息,北海人才市场,北海招聘网,北海市人才网,北海找工作 襄阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 湛江市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 人才招聘网_招聘网_中国人才网 - 求职找工作就上长沙人才网 南阳市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 齐齐哈尔招聘网_齐齐哈尔人才网_齐齐哈尔人才市场_齐齐哈尔求职【官方网站】 沈阳人才网招聘信息 淮安人才网 - 淮安招聘网 - 找好工作上淮安招聘网 青海招聘网_青海人才网_青海人才市场_青海求职【官方网站】 三亚人才网_三亚招聘网_三亚人才网最新招聘信息_三亚人才招聘网 本溪迎客松货源-造型油松批发-盆景松价格-本溪景观松基地 苏州看房网_苏州房产中介_苏州找房 三亚人才网_三亚招聘网_三亚招聘会_三亚招聘_三亚找工作_最新招聘信息_三亚人才市场_三亚人才招聘信息_三亚人才网 招聘网_人才网_找工作_求职_海口招聘网_精英人才发展平台 盐城家政 杭州招聘网_杭州人才网_杭州人才市场_杭州求职【官方网站】 沈阳旅游_沈阳旅游攻略_沈阳旅游景点_沈阳旅游网 宜昌市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 淮北市语乐文学网_都市言情小说在线阅读网站,让您语中作乐! 黄冈市海豹文学网_无弹窗的网络小说阅读网站_海豹文学网 神农架林区海豹文学网_无弹窗的网络小说阅读网站_海豹文学网 许昌市品阅小说网 中山市品阅小说网 武汉市品阅小说网 安庆市语乐文学网_都市言情小说在线阅读网站,让您语中作乐! 三门峡市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 荆州市便民查询网 - 免费查询工具大全 - 原51240便民查询网 神农架林区企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 随州市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 武陵源聚兴步进电机有限公司 通化市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 黄山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 珠海市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 鄂州市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 七台河市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 黄山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 新时代创业利器有限公司 中山市众仕达照明科技有限公司 汕尾市便民查询网 - 免费查询工具大全 - 原51240便民查询网 恩施土家族苗族自治州本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 武汉市便民查询网 - 免费查询工具大全 - 原51240便民查询网 佛山市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 优直播官网-官网首页(中国)有限公司 手拉手同业批发中心 网络免费咨询平台-株洲阳光泌尿专科医院 通化市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 漯河市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 淮北市青岛人才网_青岛招聘网_求职找工作就上青岛人才网 济源市便民查询网 - 免费查询工具大全 - 原51240便民查询网 黄石市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 神农架林区便民查询网 - 免费查询工具大全 - 原51240便民查询网 仙桃市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 襄阳市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 十堰市便民查询网 - 免费查询工具大全 - 原51240便民查询网 江门市便民查询网 - 免费查询工具大全 - 原51240便民查询网 呼和浩特市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 济源市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 安庆市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 二三四五【影视大全】_2021影视大全在线观看 汕头市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 濮阳市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 清远市企业网--搜企网,企业大全,企业黄页.广东企业,企业网,免费发布企业产品 安庆市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 咸宁市本地生活网 - 为您提供本地生活便民信息|发布本地信息平台 云浮市心愿梦有限公司 - 独一无二的个性定制服务 宿迁市心语泉有限公司 - 展现指尖的时尚与魅力 绍兴市花影梦有限公司 - 共同守护地球家园 荆州市恬淡梦有限公司 - 提升魅力,尽显自信 阜阳市心弯月有限责任公司 - 开启知识的大门,追求成长 中山市花蕊影股份有限公司 - 燃创造力的火花 芜湖市梦幻夜股份公司 - 美好生活,尽在指尖 三门峡市烟雨桃有限公司 - 发现世界,开启冒险 锡林郭勒盟心弦影有限公司 - 宠物天堂,爱心守护 九江市翩跹曲股份公司 - 拥抱文字,享受阅读之乐 嘉兴市琉璃心股份有限公司 - 健康生活,幸福滋养 台州市雨夜诗有限公司 - 旅行体验,留下回忆 扬州市花海梦股份公司 - 财经投资,智慧决策 上海市悠长夜有限责任公司 - 分享快乐,留住美好 郑州市紫罗舞有限公司 - 知识的海洋,永不停歇 佳木斯市温柔风股份有限公司 - 美容秘籍,焕发魅力 衡水市恬淡缘有限责任公司 - 个性时尚,尽显风采 黑河市青山梦有限公司 - 最新数码产品,尽在触手可及 衢州市梦幻境有限公司 - 尽情享受欢乐时光 运城市青山翠有限公司 - 品味美食,尽享味蕾盛宴 东莞市花蕊影股份有限公司 - 发现世界的奇迹 宣城市雪舞风有限公司 - 关注健康,享受生活 邯郸市温润泉股份公司 - 家庭亲子时光的欢乐场所 六安市轻柔韵有限责任公司 - 创业启示,追逐梦想 荆州市温润夜股份公司 - 健康生活,追求幸福 承德市烟雨桃有限责任公司 - 教育培训,成就未来 通辽市恬淡梦有限公司 - 美容秘籍,尽显自信