经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++成员函数中const的使用详解
来源:jb51  时间:2022/3/14 9:45:44  对本文有异议

const 在C++中是一个很重要的关键字,其不光可以用来修饰变量,还可以放在函数定义中,这里整理了其在函数中的三个用法。

修饰入参

首先我们要明白在C++中调用函数时存在两种方法,即传递值和传递引用。

值传递

值传递时,调用函数时会创建入参的拷贝,函数中的操作不会对原值进行修改,因此这种方式中不需要使用 const 来修饰入参,因为其只是对拷贝的临时对象进行操作。

址传递

传递地址时函数中的操作实际上是直接对原来的值进行修改,因此我们这里可以使用 const 修饰入参。

const修饰入参

当const修饰函数入参时表示该参数不能被修改,这个是最好理解的,比如一个函数的功能是拷贝,那么入参中的源文件都会用 const 修饰。

  1. void A::show(const int *b) {
  2. cout << "show const";
  3. // error: read-only variable is not assignable
  4. // *b = 2;
  5. cout << b << endl;
  6. }

接下来我们要关注的是这里 const 对于函数重载的作用,这里给出结论,欢迎大家讨论,对应按值传递的函数来说 const 不会有重载的效果,但是传递指针和引用是会有重载的效果。

  1. void A::show(const int b)
  2. // void A::show(int b) // error class member cannot be redeclared
  3. void display(int *num); // overload
  4. void display(const int *num); // overload
  5. void fun(A &a); // overload
  6. void fun(const A &a); // overload

函数重载的关键是函数的参数列表——即函数特征标(function signature)。如果两个函数的参数数目和类型相同,并且参数的排列顺序也相同,则他们的特征标相同,而变量名是无关紧要的。

总结一下注意点:

  • 如果输入参数采用“值传递”,**由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加 const 修饰。**例如不要将函数 void Func1(int x) 写成 void Func1(const int x)
  • 如果参数作为输出参数,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能(因为有 const 修饰之后,不能改变他的值)。
  • 果参数作为输入参数,可以防止数据被改变,起到保护作用,增加程序的健壮性,建议是能加const尽量加上

上述测试代码如下:

  1. #include <iostream>
  2. using namespace std;
  3. class A {
  4. private:
  5. int a;
  6. public:
  7. A(int a) {
  8. this->a = a;
  9. }
  10. void show(int b);
  11. // error redeclared
  12. // void show(const int b);
  13. void display(int *num); // ok
  14. void display(const int *num); // ok
  15. void fun(A &a);
  16. void fun(const A &a);
  17. void happy(int * h);
  18. void hour(const int * h);
  19. };
  20. void A::show(int b) {
  21. cout << "show: " << b << endl;
  22. }
  23. void A::display(int *num) {
  24. cout << "display:" << *num << endl;
  25. }
  26. void A::display(const int *num) {
  27. cout << "const display:" << *num << endl;
  28. }
  29. void A::fun(A &obj) {
  30. cout << "fun: " << obj.a << endl;
  31. }
  32. void A::fun(const A &obj) {
  33. cout << "const fun: " << obj.a << endl;
  34. }
  35. void A::happy(int *h) {
  36. cout << "happy:" << *h << endl;
  37. }
  38. void A::hour(const int *h) {
  39. cout << "const hour:" << *h << endl;
  40. }
  41. int main() {
  42. A a(1);
  43. const A a2(11);
  44. int b1 = 2;
  45. const int b2 = 3;
  46. // test overload
  47. a.show(b1);
  48. a.show(b2);
  49. a.display(&b1);
  50. a.display(&b2);
  51. a.fun(a);
  52. a.fun(a2);
  53. // test const
  54. a.happy(&b1);
  55. // a.happy(&b2); // error cannot initialize a parameter of type 'int *' with an rvalue of type 'const int *'
  56. a.hour(&b1);
  57. a.hour(&b2);
  58. return 0;
  59. }
  60. // ouptut
  61. show: 2
  62. show: 3
  63. display:2
  64. const display:3
  65. fun: 1
  66. const fun: 11
  67. happy:2
  68. const hour:2
  69. const hour:3

修饰返回值

const 修饰返回值时,表示返回值不能被修改。需要注意的是如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加 const 修饰没有任何价值。如果返回的是引用或指针,表示不能修改指向的数据。

一般用得多的是返回值是引用的函数, 可以肯定的是这个引用必然不是临时对象的引用, 因此一定是成员变量或者是函数参数, 所以在返回的时候为了避免其成为左值被修改,就需要加上const关键字来修饰。

我们可以看如下代码示例:

  1. #include <iostream>
  2. using namespace std;
  3. class Alice {
  4. private:
  5. int a;
  6. public:
  7. Alice(int a): a(a) {}
  8. int get_a() {return a;}
  9. const int* get_const_ptr() {return &a;}
  10. int* get_ptr() {return &a;}
  11. };
  12. int main() {
  13. Alice alice(1);
  14. int a1 = alice.get_a(); // ok
  15. cout << a1 << endl;
  16. const int a2 = alice.get_a(); // ok
  17. cout << a2 << endl;
  18. // error cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'
  19. // int* b1 = alice.get_const_ptr();
  20. const int* b2 = alice.get_const_ptr(); // ok
  21. cout << *b2 << endl; // ok
  22. // *b2 = 3; // error read-only variable is not assignable
  23. *(alice.get_ptr()) = 3;
  24. cout << alice.get_a() << endl; // 3
  25. return 0;
  26. }

修饰函数

const 也可以用来放在函数末尾,用来修饰成员函数,表明其是一个常成员函数,这个对于初次接触C++的同学来说会有点陌生,不过这也是C++中严谨的地方。先看代码示例,学习任何编程技术都一定要写对应的代码,把它跑起来并分析结果才算是真正学会了,不会你只是知道了这个知识点,只知其然而不知其所以然。纸上得来终觉浅,绝知此事要躬行,这里的要躬行指的就是写代码。

首先来看如下的代码

  1. class Alice {
  2. private:
  3. int a;
  4. public:
  5. Alice(int a): a(a) {}
  6. void show();
  7. };
  8. void Alice::show() {
  9. cout << "hello Alice" << endl;
  10. }
  11. int main() {
  12. const Alice a(1);
  13. // error: 'this' argument to member function 'show' has type 'const Alice', but function is not marked const
  14. // a.show();
  15. return 0;
  16. }

上述代码会报错,因为 show() 方法不是常成员函数,而 a 是常对象。本质上,成员函数中都有一个隐含的入参 this, 这个 this指的就是调用该方法的对象,而如果在函数的后面加上 const,那么这个 const 实际上修饰的就是这个 this。也就是说函数后加上了 const,表明这个函数不会改变调用者对象。

这里借用侯捷老师的图片

在这里插入图片描述

上面图片表明,在正常情况下:

  • non-const对象可以调用const 或者 non-const 成员函数
  • const 对象 只可以调用 const 成员函数

补充一点,**如果成员函数同时具有 const 和 non-const 两个版本的话, const 对象只能调用const成员函数, non-const 对象只能调用 non-const 成员函数。**如以下代码示例

  1. #include <iostream>
  2. using namespace std;
  3. class R {
  4. public:
  5. R(int r1, int r2) {
  6. a = r1;
  7. b = r2;
  8. }
  9. void print();
  10. void print() const;
  11. private:
  12. int a;
  13. int b;
  14. };
  15. void R::print() {
  16. cout << "normal print" << endl;
  17. cout << a << ", " << b << endl;
  18. }
  19. void R::print() const {
  20. cout << "const print" << endl;
  21. cout << a << ", " << b << endl;
  22. }
  23. int main() {
  24. R a(5, 3);
  25. a.print();
  26. const R b(6 ,6);
  27. b.print();
  28. return 0;
  29. }
  30. // output
  31. normal print
  32. 5, 3
  33. const print
  34. 6, 6

这里也是建议能加 const 的时候就加。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注w3xue的更多内容! 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号