原始链接

1. const含义

常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。

2. const作用

3. const对象默认为文件局部变量

4. 指针与const

5. 定义常量

6. 函数中使用const

const修饰函数返回值

这个跟const修饰普通变量以及指针的含义基本相同:

1. const int

const int func1();
这个本身无意义,因为参数返回本身就是赋值给其他的变量!

2. const int*

const int* func2();
指针指向的内容不变。

3. int *const

int *const func2();
指针本身不可变。

const修饰函数参数

这个跟const修饰普通变量以及指针的含义基本相同:

1. 传递过来的参数及指针本身在函数内不可变,无意义!

  1. void func(const int var); // 传递过来的参数不可变
  2. void func(int *const var); // 指针本身不可变

表明参数在函数体内不能被修改,但此处没有任何意义,var本身就是形参,在函数内不会改变。包括传入的形参是指针也是一样。
输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。

2. 参数指针所指内容为常量不可变

  1. void StringCopy(char *dst, const char *src);

其中src 是输入参数,dst 是输出参数。给src加上const修饰后,如果函数体内的语句试图改动src的内容,编译器将指出错误。这就是加了const的作用之一。

3. 参数为引用,为了增加效率同时防止修改

  1. void func(const A &a)

对于非内部数据类型的参数而言,象void func(A a)这样声明的函数注定效率比较低。因为函数体内将产生A 类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。
为了提高效率,可以将函数声明改为void func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临 时对象。
但是函数void func(A &a) 存在一个缺点:
“引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为 void func(const A &a)。
以此类推,是否应将void func(int x) 改写为void func(const int &x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。
小结:
1.对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。例如将void func(A a) 改为void func(const A &a)。
2.对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void func(int x) 不应该改为void func(const int &x)。

以上解决了两个面试问题:

  • 如果函数需要传入一个指针,是否需要为该指针加上const,把const加在指针不同的位置有什么区别;
  • 如果写的函数需要传入的参数是一个复杂类型的实例,传入值参数或者引用参数有什么区别,什么时候需要为传入的引用参数加上const。

    7. 类中使用const

    在一个类中,任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改 数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性。
    使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常量或常对象,没有使用const关键字进行说明的成员函数不能用来操作常对象。
    对于类中的const成员变量必须通过初始化列表进行初始化,如下所示: ```cpp class Apple{ private: int people[100]; public: Apple(int i); const int apple_number; };

Apple::Apple(int i):apple_number(i) {

}

  1. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.<br />例如:
  2. ```cpp
  3. //apple.h
  4. #pragma once
  5. class Apple
  6. {
  7. private:
  8. int people[100];
  9. public:
  10. Apple(int i);
  11. const int apple_number;
  12. void take(int num) const;
  13. int add0(int num);
  14. int add(int num);
  15. int add(int num) const;
  16. int getCount(int num) const;
  17. };
  1. //apple.cpp
  2. #include "apple.h"
  3. #include <iostream>
  4. using namespace std;
  5. Apple::Apple(int i) :apple_number(i)
  6. {
  7. }
  8. int Apple::add0(int num)
  9. {
  10. cout << "add0 func " << num << endl;
  11. take(num);
  12. return num;
  13. }
  14. int Apple::add(int num)
  15. {
  16. cout << "add func " << num << endl;
  17. take(num);
  18. return num;
  19. }
  20. int Apple::add(int num) const
  21. {
  22. cout << "add func const" << num << endl;
  23. take(num);
  24. return num;
  25. }
  26. void Apple::take(int num) const
  27. {
  28. cout << "take func const" << num << endl;
  29. }
  30. int Apple::getCount(int num) const
  31. {
  32. cout << "getCount const" << num << endl;
  33. take(num);
  34. //add0(num); //error
  35. return apple_number;
  36. }
  1. //main.cpp
  2. #include<iostream>
  3. #include"apple.h"
  4. using namespace std;
  5. int main() {
  6. Apple a(2);
  7. cout << a.getCount(2) << endl;
  8. a.add(10);
  9. const Apple b(3);
  10. b.add(100);
  11. return 0;
  12. }

编译: g++ -o main main.cpp apple.cpp
结果:

  1. getCount const2
  2. take func const2
  3. add func const2
  4. take func const2
  5. 2
  6. add func 10
  7. take func const10
  8. add func const100
  9. take func const100

上面getCount()方法中调用了一个add0方法,而add方法并非const修饰,所以运行报错。也就是说const对象只能访问const成员函数。
而add方法又调用了const修饰的take方法,证明了非const对象可以访问任意的成员函数,包括const成员函数。
除此之外,我们也看到add的一个重载函数,也输出了两个结果,说明const对象默认调用const成员函数。
我们除了上述的初始化const常量用初始化列表方式外,也可以通过下面方法:
第一:将常量定义与static结合,也就是:

  1. static const int apple_number

第二:在外面初始化:

  1. const int Apple::apple_number=10;

当然,如果你使用c++11进行编译,直接可以在定义出初始化,可以直接写成:

  1. static const int apple_number=10;
  2. // 或者
  3. const int apple_number=10;

这两种都在c++11中支持!
编译的时候加上-std=c++11即可!
这里提到了static,下面简单的说一下:
在C++中,static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现文件中初始化。
在类中声明:

  1. static int ap;

在类实现文件中使用:

  1. int Apple::ap=666

对于此项,c++11不能进行声明并初始化,也就是上述使用方法。