感谢原创作者,写的好详细。不忍错过,所以转载过来了。。。

原文地址:

https://www.cnblogs.com/icemoon1987/p/3320326.html

在这篇文章中,我总结了一些C/C++语言中的 const 修饰符的常见用法,供大家参考。 const 的用法,也是技术性面试中常见的基础问题,希望能够帮大家梳理一下知识,给大家一点点帮助。作者是菜鸟一枚,难免出错,还望各位大牛不吝赐教。

  首先,来看看const的基本含义。在 C/C++ 语言中,const关键字是一种修饰符。所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码。就 const 修饰符而言,它用来告诉编译器,被修饰的这些东西,具有“只读”的特点。在编译的过程中,一旦我们的代码试图去改变这些东西,编译器就应该给出错误提示。

  所以,const修饰符的作用主要是利用编译器帮助我们检查自己代码的正确性。我们使用const在源码中标示出“不应该改变”的地方,然后利用编译器,帮助我们检查这些地方是否真的没有被改变过。如果我们不小心去修改了这些地方,编译器就会报错,从而帮助我们纠正错误。使用const和不使用const,对于最终编译产生的代码并没有影响。

  虽然const对于最终代码没有影响,但是尽可能使用const,将帮助我们避免很多错误,提高程序正确率。

  在C/C++中,常见 const 用法有以下几种:

一、const 变量

  const 变量指的是,此变量的值是只读的,不应该被改变。

  • 如果我们在程序中试图修改 const 变量的值,在编译的时候,编译器将给出错误提示。
  • 正因为 const 变量的值在给定以后不能改变,所以 const 变量必须被初始化。(如果不初始化,之后还怎么赋值呢?)如果我们不初始化 const 变量,编译时也会有错误提示。
  1. const int debugLevel = 10;
  2. const int logLevel; // 编译错误:未初始化const变量(这个错误是否提示,和所用的编译器有关)
  3.  
  4. debugLevel = 5; // 编译错误:给只读变量赋值

  在C++中,const 全局变量被用来替换一般常量宏定义。因为虽然 const 变量的值不能改变,但是依然是变量,使用时依然会进行类型检查,要比宏定义的直接替换方法更严格一些(下文还会讨论这个问题)。

  结构体变量也是一种变量,const 结构体变量是什么含义呢?

  1. 1 struct debugInfo
  2. 2 {
  3. 3 int debugLevel;
  4. 4 int line;
  5. 5 };
  6. 6
  7. 7 int main( int argc, char *argv[])
  8. 8 {
  9. 9 const struct debugInfo debug_const1; // 编译错误:未初始化只读变量(与编译器实现有关)
  10. 10
  11. 11 struct debugInfo debug_not_const;
  12. 12
  13. 13 debug_not_const.debugLevel = 10;
  14. 14 debug_not_const.line = 5;
  15. 15
  16. 16 const struct debugInfo debug_const2 = debug_not_const;
  17. 17
  18. 18 debug_const2.debugLevel = 10; // 编译错误:不允许修改只读变量
  19. 19 debug_const2.line = 2; // 编译错误:不允许修改只读变量
  20. 20
  21. 21 return 0;
  22. 22 }

  在C中,const 结构体变量表示结构体中任何数据域均不允许改变,且需要另一个结构体变量进行初始化。在C++中,struct与class除了默认访问权限之外,并无本质区别。在下一节进行讨论。

二、const 类对象

  const类对象指的是,此类对象不应该被改变。

  • const 类对象与 const 变量并无实质不同,只在于类对象的 “改变” 定义。
  • 类对象的 “改变” 定义:改变任何成员变量的值,调用任何非const成员函数
  1. class CDebugModule
  2. {
  3. public:
  4. CDebugModule() {};
  5. ~CDebugModule() {};
  6. public:
  7. int m_debugLevel;
  8.  
  9. public:
  10. void SetDebugLevel(int debugLevel) { m_debugLevel = debugLevel;};
  11. void PrintDebugLevel(void) { cout << m_debugLevel;};
  12. void PrintDebugLevel_const(void) const { cout << m_debugLevel;}; // const 类成员函数
  13. };
  14.  
  15. int main( int argc, char *argv[])
  16. {
  17. const CDebugModule debug;
  18.  
  19. debug.m_debugLevel = 10; // 编译出错:不能直接改变成员变量
  20. debug.SetDebugLevel(20); // 编译出错:不能通过成员函数改变成员变量
  21. debug.PrintDebugLevel(); // 编译出错:不能调用非 const 成员函数
  22. debug.PrintDebugLevel_const(); // 正常
  23.  
  24. return 0;
  25. }

  不能改变 const 类对象的任何成员变量,这一点比较好理解,因为 const 本身就带有不可改变变量取值(内部状态)的含义。为何const 类成员不能调用非const成员函数呢?我们将在 第九节“const 成员函数” 进行探讨。在C++中,struct和class没有明显差别,不再赘述。

三、指向 const 变量的指针

  指向 const 变量的指针,指的是一个指针,其中保存着一个 const 变量的地址。

  • 由于指针指向一个 const 变量,所以通过指针,不能修改这个 const 变量的值。
  • 虽然指针指向的值不能改变,但是指针的指向可以改变。
  1. const int debugLevel = 10;
  2. const int logLevel = 10;
  3.  
  4. const int *p = &debugLevel;
  5. p = &logLevel; // 正常,指针的指向可以改变
  6.  
  7. *p = 10; // 编译错误,指针指向的位置是只读的

  

  在 *p = 10, 这一句,编译器是通过“指针的类型”(const int *)还是通过其“指向变量的类型”(const int )来判断只读的呢?我们可以通过下面这个小程序来求证一下:

  1. 1 const int debugLevel = 10; // const 变量
  2. 2 int logLevel = 10; // 普通变量
  3. 3
  4. 4 const int *p;
  5. 5 int *q;
  6. 6
  7. 7 p = &logLevel; // 我们让指向 const 变量的指针指向一个普通变量
  8. 8 q = (int*)&debugLevel; // 让指向普通变量的指针,指向一个 const 变量
  9. 9
  10. 10 *q = 5; // 编译正常
  11. 11 *p = 5; // 编译出错:位置为只读

  通过10、11行程序的编译结果,我们可以看出,如果指针的类型为“指向const变量的指针”,即使其指向的内容是非const变量,也无法通过这个指针改变数据内容。反之,如果指针的类型是“指向非const变量的指针”,即使指向的是const变量,也可以通过这个指针改变const变量的内容(稍后讨论这一点)。所以,编译器是通过 “指针的类型” 来判断是否只读的。

  说到这点,我觉得可以这么解释。因为我们没有使用面向对象编程,也就不具备动态判断对象具体类型的能力。所以,编译器只能够静态地判断对象的类型。这样,编译器就只能识别出指针的类型,而不清楚指针指向的内容的具体类型了。当然也就只能通过指针类型来判断内容是否只读了。

  在上面,我们通过指针,“改变”了const变量的内容,如果我们在上边的程序中添加上输出,会是什么结果?

  1. 12 printf("debugLevel = %d\n", debugLevel);
  2. 13 printf("*q = %d\n", *q);
  3.  
  4. 14 printf("debugLevel address = %x\n", &debugLevel);
  5. 15 printf("q = %x\n", q);

  从上边的说明,我们可以想象,debugLevel的值,被我们通过指针改变了,所以输出应该是:

  1. debugLevel = 5
  2. *q = 5
  3. debugLevel address = 0xbfaff718
  4. q = 0xbfaff718

  但是,事实上,这个结果是不确定的!跟您所用的编译器和优化级别有关。我在g++ 4.1.2上,编译运行得出了以下结果:

  1. debugLevel = 10 // 直接打印可以发现,const 变量的值未改变 !
  2. *q = 5 // 通过指针访问,发现 const 变量的值改变了!
  3. debugLevel address = 0xa6a65318
  4. q = 0xa6a65318 // 指针的指向并没有错误

  乍一看,好像同一个地址的东西,采用变量名访问和采用指针访问,得到的结果竟然不一样。其实,之所以产生这种结果,是由于在编译器变异的过程中,对 const 变量的访问进行了优化。编译器将 const 变量直接替换为对应的内容。也就是说,在编译的过程中 :

  1. printf("debugLevel = %d\n", debugLevel);

这个语句,被直接替换成了:

  1. printf("debugLevel = %d\n", 10);

所以,才产生了上边的现象。当然,这种替换不一定会发生,跟编译器和优化等级相关。

  上文已经提到了,C++建议使用 const 全局变量来替换一般常量的宏定义。通过这个例子可以看出,使用 const 全局变量之后,由于编译器会替换其为具体内容,所以在程序实际运行中,并不会产生一次变量访问,也就使得 const 全局变量和宏定义具有相同的执行效率。同时,使用 const 全局变量,可以让编译器帮助我们进行变量类型检查,提高正确率。

  指针也是变量的一种,所以自然有 const 类型指针。

四、const 指针

  const指针指的是,一个指针本身经过 const 修饰,自身内容(指针指向)不应该发生改变。

  • 指针的指向一经确定,不能改变。指针指向的内容,可以改变。
  1. int logLevel = 10;
  2. int logId = 0;
  3.  
  4. int * const p = &logLevel;
  5. int * const q; // 编译错误,未初始化 const 变量(这个错误是否报告,和所用的编译器有关)
  6.  
  7. *p = 5; // 正常,const指针指向内容可以改变
  8. p = &logId // 编译错误,const指针自身内容(指向)不能改变

  指针也是一种变量,只不过其内容保存的是地址而已。所以const指针的内容不能改变,也即是它的指向不能改变。

  const指针和指向const变量的指针,在写法上容易使人混淆。给大家介绍一种我自己用着比较顺手的区分方法:从右向左,依次结合,const就近结合。

  比如,int * const p 可以这样进行解读:

  1、int * ( const p ):变量p 经过 const 修饰,为只读变量。

  2、int (* (const p)):(const p 现在作为一个整体) 只读变量p是一个指针。

  3、(int (* (const p))):(同样的 * const p 作为一个整体) 这个只读的指针p,指向一个int型变量。

  于是,可以区分出 int * const p 是一个指向 int 型的const指针。

  再比如,const int * p 可以这样解读:

  1、const int (* p):变量p是一个指针。

  2、(const int) (* p):(const与就近的 int 结合)这个指针指向 const int 型变量。

  所以,const int * p 是一个指向 const 整形变量的指针。

  采用这个方法,相信大家可以自己分辨 int const * p的含义了。

  值得注意的是,有的编译器对重复的 const 不会报错!所以允许像 const int const *p; 这种写法。在分析这种“错误”的写法时,只要把重复修饰的const忽略即可。

五、指向 const 变量的 const 指针

  这种情况是 const 指针和 指向 const 变量的指针的结合,相信大家已经能够自己分析,不再赘述。

六、const 变量作为函数参数

  在函数调用的过程中,函数的参数是建立在函数的栈上的变量。既然是变量,就可以通过 const 进行修饰。

  • 将函数参数声明为 const 类型,表示对于函数来说,这个参数是一个 const 变量。也就是说,函数内部不能够改变这个参数的值。
  • 将函数参数是一个指针,把它声明为 “指向 const 变量的指针” ,允许上层使用 ”指向 const 变量的指针“ 或 普通指针 作为参数,调用函数。(如果参数声明的是普通指针,则不允许使用 指向 const 变量的指针 作为参数调用)(与编译器有关)
  1. 1 // 接收一个int变量,并在函数内部,认为它是只读的
  2. 2 void OutputInt_const( const int a )
  3. 3 {
  4. 4 a = 5; // 编译错误:不允许修改只读变量
  5. 5 printf("a = %d\n", a);
  6. 6 }
  7. 7
  8. 8 // 接收一个int变量,在函数内部,认为它是普通的
  9. 9 void OutputInt_not_const( int a )
  10. 10 {
  11. 11 a = 5; // 正常
  12. 12 printf("a = %d\n", a);
  13. 13 }
  14. 14
  15. 15 // 接收一个 指向const型整形数的指针
  16. 16 void OutputInt_p_const( const int *a )
  17. 17 {
  18. 18 *a = 5; // 编译错误:
  19. 19 printf("*a = %d\n", *a);
  20. 20 }
  21. 21
  22. 22 // 接收一个普通指针
  23. 23 void OutputInt_p_not_const( int *a )
  24. 24 {
  25. 25 *a = 5;
  26. 26 printf("*a = %d\n", *a);
  27. 27 }
  28. 28
  29. 29 // 主函数
  30. 30 int main( int argc, char *argv[])
  31. 31 {
  32. 32 int logLevel = 10;
  33. 33 const int debugLevel = 5;
  34. 34
  35. 35 OutputInt_const(logLevel);
  36. 36 OutputInt_const(debugLevel);
  37. 37
  38. 38 OutputInt_not_const(logLevel);
  39. 39 OutputInt_not_const(debugLevel);
  40. 40
  41. 41 OutputInt_p_const(&logLevel);
  42. 42 OutputInt_p_const(&debugLevel);
  43. 43
  44. 44 OutputInt_p_not_const(&logLevel);
  45. 45 OutputInt_p_not_const(&debugLevel); // 编译错误:从 const int * 到 int * 转换失败(与编译器有关)
  46. 46
  47. 47 return 0;
  48. 48 }

  为什么对于指针参数的要求特殊?其实我们可以仔细想一下 const 在修饰参数时的作用。

  首先,函数参数是函数内部可见的一个变量。在const 修饰函数参数时,仅仅表示此函数内部对于这个变量的限制。对于传进来的参数,在外边究竟是什么样子的,函数内部并不关心。所以,函数 void OutputInt_const( const int a ) 并不会在意传入的参数在main函数中是否是只读的。它只会在函数内部,将入参当作只读变量处理。

  既然 const 修饰函数参数时,不会限制入参是否为只读,为什么 OutputInt_p_not_const( int *a ) 和 OutputInt_p_const( const int *a ) 的调用方式有区别呢(见44、45行)?

  其实答案很简单,const 在此处并不是修饰函数参数的!此处的 const ,与 int * 组合,描述了参数的一种类型。OutputInt_p_const函数要求的参数是:指向只读整形的指针。所以,只要调用时传入的参数不是一个指向只读整形数的指针,就会发生类型不匹配。在示例41行的调用中,使用一个 int * 来调用 OutputInt_p_const 函数,发生类型不匹配,但是 int * 可以隐式转换为 const int *,所以此处调用可以成功。但在45行中,采用 const int * 来调用需要 int * 的 OutputInt_p_not_const 函数,发生类型不匹配, const int * 不能够隐式转换为 int *,所以此处调用失败。

  为什么 int * 可以隐式转换为 const int *,但是反向就不可以呢?相信各位读者已经想到了。隐式转换不放宽对于变量的要求,而 const 型的变量显然比非 const 型变量要求严格,所以不能由 const int * 转为 int *。

七、const 返回值

  const 型的返回值,指的是函数的返回值为一个 const 变量。

  • 函数返回const返回值,主要用于函数返回const引用。
  1. 1 #include <string>
  2. 2
  3. 3 using namespace std;
  4. 4
  5. 5 // 返回 const 引用的函数
  6. 6 const string& SetVersion_const(string & versionInfo)
  7. 7 {
  8. 8 versionInfo = "V0.0.3";
  9. 9 return versionInfo;
  10. 10 }
  11. 11
  12. 12 // 返回普通引用的函数
  13. 13 string& SetVersion_not_const(string & versionInfo)
  14. 14 {
  15. 15 versionInfo = "V0.0.3";
  16. 16 return versionInfo;
  17. 17 }
  18. 18
  19. 19 // 主函数
  20. 20 int main( int argc, char *argv[])
  21. 21 {
  22. 22 string versionInfo;
  23. 23
  24. 24 SetVersion_const(versionInfo) = "V0.0.5"; // 编译错误,返回的引用为 const 引用,不允许修改。
  25. 25
  26. 26 SetVersion_not_const(versionInfo) = "V0.0.5"; // 正常,返回的引用为普通引用,可以修改内容。
  27. 27
  28. 28 return 0;
  29. 29 }

  引用是一个对象的别名,相当于 const 指针,其指向一经确定,就不能改变了。而 const 引用,则相当于指向 const 变量的 const 指针,其指向和指向的内容均不允许改变。所以在函数返回 const 引用时,不能够通过函数返回的引用对实际对象进行任何修改,即便对象本身不是 const 的。在本例中,versionInfo 在 main 函数中不是const的。SetVersion_const 函数返回了一个指向 versionInfo 的 const 引用,不能通过此引用,对 versionInfo 进行修改。

  为什么会出现这种现象?相信大家都能理解了。请参考 指向 const 变量指针 的相关内容。

八、const 成员变量

  const 成员变量指的是类中的成员变量为只读,不能够被修改(包括在类外部和类内部)。

  • const 成员变量必须被初始化(在相关构造函数的初始化列表中),初始化后,不能够被修改
  • 静态 const 成员变量需要在类外部单独定义并初始化(可定义在头文件)
  1. 1 class CDebugModule
  2. 2 {
  3. 3 public:
  4. 4 CDebugModule();
  5. 5 ~CDebugModule();
  6. 6
  7. 7 public:
  8. 8 const int m_debugLevel;
  9. 9 static const int m_debugInfo;
  10. 10
  11. 11 };
  12. 12
  13. 13 const int CDebugModule::m_debugInfo = 1; // 静态常量成员需要在类外进行单独定义和初始化
  14. 14
  15. 15 CDebugModule::CDebugModule()
  16. 16 : m_debugLevel(10) // const 成员在构造函数初始化列表中初始化
  17. 17 {
  18. 18 }
  19. 19
  20. 20 CDebugModule::~CDebugModule()
  21. 21 {
  22. 22 }
  23. 23
  24. 24 int main(int argc, char *argv[])
  25. 25 {
  26. 26 CDebugModule debugModule;
  27. 27
  28. 28 debugModule.m_debugLevel = 10; // 编译错误,不能改变只读成员
  29. 29 CDebugModule::m_debugInfo = 10; // 编译错误,不能改变只读成员
  30. 30
  31. 31 return 0;
  32. 32 }

  类对象的实例化过程可以理解为包含以下步骤:首先,开辟整个类对象的内存空间。之后,根据类成员情况,分配各个成员变量的内存空间,并通过构造函数的初始化列表进行初始化。最后,执行构造函数中的代码。由于 const 成员变量必须在定义(分配内存空间)时,就进行初始化。所以需要在够在函数的初始化列表中初始化。const成员在初始化之后,其值就不允许改变了,即便在构造内部也是不允许的。

  静态成员变量并不属于某个类对象,而是整个类共有的。静态成员变量可以不依附于某个实例化后的类对象进行访问。那么,静态成员变量的值,应该在任何实例化操作之前,就能够进行改变(否则,只有实例化至少一个对象,才能访问静态成员)。所以,静态成员变量不能够由构造函数进行内存分配,而应该在类外部单独定义,在实例化任何对象之前,就开辟好空间。又由于 const 成员变量 必须初始化,所以静态成员变量必须在定义的时候就初始化。

九、const 成员函数

  const成员函数指的是,此函数不应该修改任何成员变量。

  • 传给const成员函数的this指针,是指向 const 对象 的 const 指针
  • const成员函数,不能够修改任何成员变量,除非成员变量被 mutable 修饰符修饰
  1. 1 class CDebugModule
  2. 2 {
  3. 3 public:
  4. 4 CDebugModule() {};
  5. 5 ~CDebugModule();
  6. 6
  7. 7 public:
  8. 8 int m_debugLevel_not_mutable; // 不带 mutable 修饰的成员变量
  9. 9 mutable int m_debugLevel_mutable; // 带 mutable 修饰的成员变量
  10. 10
  11. 11 public:
  12. 12 void SetDebugLevel_not_const(int debugLevel); // 非 const 成员函数
  13. 13 void SetDebugLevel_const(int debugLevel) const; // const 成员函数
  14. 14 };
  15. 15
  16. 16 void CDebugModule::SetDebugLevel_not_const(int debugLevel)
  17. 17 {
  18. 18 m_debugLevel_not_mutable = debugLevel;
  19. 19 m_debugLevel_mutable = debugLevel;
  20. 20 return;
  21. 21 }
  22. 22
  23. 23 void CDebugModule::SetDebugLevel_const(int debugLevel) const
  24. 24 {
  25. 25 m_debugLevel_not_mutable = debugLevel; // 编译错误,const 成员函数不能修改一般的成员变量
  26. 26 m_debugLevel_mutable = debugLevel; // 正常,当成员变量被 mutable 修饰时,const成员函数就能修改了
  27. 27 return;
  28. 28 }
  29. 29
  30. 30 int main(int argc, char *argv[])
  31. 31 {
  32. 32 CDebugModule debugModule;
  33. 33
  34. 34 debugModule.SetDebugLevel_not_const(10);
  35. 35 debugModule.SetDebugLevel_const(10);
  36. 36
  37. 37 return 0;
  38. 38 }

  在成员函数调用的过程中,都有一个 this 指针被当做参数隐性地传递给成员函数(可能通过栈,也可能通过CPU寄存器)。这个this指针,指向调用这个函数的对象(这样,成员函数才能找到成员变量的地址,从而对其进行操作)。这个this指针,是个 const指针,不能修改其指向(你不希望这个对象的函数,修改了那个对象的成员变量,对吧?)。

  传递给const成员函数的this指针,指向一个const对象。也就是说,在const成员函数内部,这个this指针是一个指向const对象的const指针。通过第二节的探讨,相信大家已经能够明白,为什么const成员函数不能修改任何成员变量了。

  mutable 修饰符使得const函数的行为有了一些灵活性。相当于提醒编译器,这个成员变量比较特殊,就不要进行任何只读检查了。

  我们在第二节留下了一个问题 “为什么 const 对象只能够调用const成员函数呢?”,其实是这样的。由于对象本身通过 const 修饰,那么指向这个对象的指针也就是指向const对象的const指针了。换句话说,指向这个对象的this指针就是指向const对象的const指针。一般成员函数要求的this指针(别忘了this指针也是一个参数)为:指向对象的const指针。所以此处发生了参数不匹配,无法进行调用。而 const 成员函数要求的this指针,恰恰是 指向const对象的const指针。所以依然能够调用。

 十、总结  

 const 变量

const int a;

不能修改值,必须初始化

const 类对象

const MyClass a;

不能修改成员变量的值,不能调用非 const 函数

 指向 const 变量的指针

const int * a;

指向内容不可变,指向可变

 const 指针

int * const a;

指向内容可变,指向不可变

 指向 const 变量的 const 指针

const int * const a;

指向内容不可变,指向也不可变

const 引用

 const 变量作为函数参数

void myfun(const int a);

函数内部不能改变此参数

指向 const 变量的指针做参数,允许上层用一般指针调用。(反之不可)

 const 返回值

const string& myfun(void);

用于返回const引用

上层不能使用返回的引用,修改对象

 const 成员变量

const int a;

static const int a;

必须在初始化列表初始化,之后不能改变

static const 成员变量需要单独定义和初始化

const 成员函数

void myfun(void) const;

this指针为 指向const对象的const指针

不能修改 非mutable 的成员变量

  本文的内容就这么多了,感谢您能够看到最后,希望对您能够有一点点帮助 ^_^

转载----C/C++ 中 const 修饰符用法总结的更多相关文章

  1. C/C++ 中 const 修饰符用法总结

    C/C++ 中 const 修饰符用法总结 在这篇文章中,我总结了一些C/C++语言中的 const 修饰符的常见用法,供大家参考. const 的用法,也是技术性面试中常见的基础问题,希望能够帮大家 ...

  2. [原创] 基础中的基础(二):C/C++ 中 const 修饰符用法总结

    在这篇文章中,我总结了一些C/C++语言中的 const 修饰符的常见用法,供大家参考. const 的用法,也是技术性面试中常见的基础问题,希望能够帮大家梳理一下知识,给大家一点点帮助.作者是菜鸟一 ...

  3. const修饰符用法

    1. 将一个对象设置为不可修改 const int a = 100; 2. 指向const对象的指针 const int* p = 3;可以通过指针来修改指针所指向的值,但是不能通过指针*p修改对像的 ...

  4. C++中 容易忽视的const 修饰符

    C++可以用const定义常量,也可以用#define定义常量,但是前者比后者有更多的有点: (1)const常量有数据类型,而宏常量没有数据类型.编译器可以对const进行类型安全检查,而后者只进行 ...

  5. Delphi 中 函数参数中的 const 修饰符的本质以及注意事项

    来自:http://blog.csdn.net/farrellcn/article/details/9096787 ------------------------------------------ ...

  6. [Reprint]C++函数前和函数后加const修饰符区别

    c++中关于const的用法有很多,const既可以修饰变量,也可以函数,不同的环境下,是有不同的含义.今天来讲讲const加在函数前和函数后面的区别.比如: 01 #include<iostr ...

  7. C++函数前和函数后加const修饰符区别

    class Test(){ public: Test(){} const int foo(int a); const int foo(int a) const; }; 一.概念 当const在函数名前 ...

  8. C/C++中const关键字的用法及其与宏定义的比较

    1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 ; ; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用c ...

  9. C/C++中const关键字的用法及其与宏常量的比较

    1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 ; ; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用c ...

随机推荐

  1. java xml文件

    xml: 是可扩展的标签语言.其中标签可以自定义. 作用是存储数据,即配置文件. 书写规范: 1:区分大小写,html不区分. 2:应该有根标签(类似html的<html>标签) 3:标签 ...

  2. HDU 2141 Can you find it? (二分)

    题目链接: Can you find it? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/ ...

  3. apue2e unp安装

    最近在读 Richard Stevens 的大作<UNIX环境高级编程>,相信很多初读此书的人都会与我一样遇到这个问题,编译书中的程序实例时会出现问题,提示 “错误:apue.h:没有那个 ...

  4. JavaScript跨源资源共享

    CORS(跨 源资源共享)基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应式应该成功还是失败 IE对CORS的实现 IE8引入了XDR类型,与XHR类似,但可以实现安 ...

  5. ios开发UI篇--UIButton

    概述 UIButton 是执行自定义代码以响应用户交互的控件. UIButton 其实包含 UIImageView 和 UILabel 两个控件,UIButton 继承于 UIControl,所以有  ...

  6. Xamarin 编写混合APP趟坑记录(二)

    前言 公司要开发一个App,为了便于维护和更新,而不用每次去苹果审核,采用的是混合开发方式:用WebVie+WebApp的方式. 因为本人不会Java和ObjectC,公司又不想花钱招这两个岗位的人, ...

  7. redis 基本数据类型-字符串(String)

    不瘦原来对redis也是有个大概的了解(就你知道的多), 但是最近和大神聊天的过程中才明白自己知道的简直就是鸡毛蒜皮(让你得瑟),所以不瘦打算从头在捋一遍,顺便把过程也记录下来,如果能给大家在学习re ...

  8. 单片机实现简易版shell的方法和原理

    Rt-thread 中有一个完整的finsh(shell )系统,使用串口做命令行输入输出.但是想要用这个炫酷的工具就必须要上rtthread系统,或者花大力气将其移植出来.于是我就自己写了一个类似于 ...

  9. JavaWeb基础—数据库连接池DBCP、C3P0

    一.基本概念 数据库连接池负责分配.管理和释放数据库连接 数据库连接池:(池用map来实现居多) 用处:为了可重用(销毁创建麻烦,开销大)(招培训老师的例子) 二.编写实现数据库连接池 池参数: 初识 ...

  10. 20145209刘一阳《JAVA程序设计》第十五周补充测试

    第十五周补充测试 1.实验楼Linux中可以通过(ABC)查看用户登录情况. A .who B .who am i C .who mom likes D .who are you 2.在 Linux ...