1. const含义
常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。
2. const作用
3. const对象默认为文件局部变量
4. 指针与const
5. 定义常量
6. 函数中使用const
const修饰函数返回值
1. const int
const int func1();
这个本身无意义,因为参数返回本身就是赋值给其他的变量!
2. const int*
3. int *const
int *const func2();
指针本身不可变。
const修饰函数参数
1. 传递过来的参数及指针本身在函数内不可变,无意义!
void func(const int var); // 传递过来的参数不可变void func(int *const var); // 指针本身不可变
表明参数在函数体内不能被修改,但此处没有任何意义,var本身就是形参,在函数内不会改变。包括传入的形参是指针也是一样。
输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。
2. 参数指针所指内容为常量不可变
void StringCopy(char *dst, const char *src);
其中src 是输入参数,dst 是输出参数。给src加上const修饰后,如果函数体内的语句试图改动src的内容,编译器将指出错误。这就是加了const的作用之一。
3. 参数为引用,为了增加效率同时防止修改
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) {
}
const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.<br />例如:```cpp//apple.h#pragma onceclass Apple{private:int people[100];public:Apple(int i);const int apple_number;void take(int num) const;int add0(int num);int add(int num);int add(int num) const;int getCount(int num) const;};
//apple.cpp#include "apple.h"#include <iostream>using namespace std;Apple::Apple(int i) :apple_number(i){}int Apple::add0(int num){cout << "add0 func " << num << endl;take(num);return num;}int Apple::add(int num){cout << "add func " << num << endl;take(num);return num;}int Apple::add(int num) const{cout << "add func const" << num << endl;take(num);return num;}void Apple::take(int num) const{cout << "take func const" << num << endl;}int Apple::getCount(int num) const{cout << "getCount const" << num << endl;take(num);//add0(num); //errorreturn apple_number;}
//main.cpp#include<iostream>#include"apple.h"using namespace std;int main() {Apple a(2);cout << a.getCount(2) << endl;a.add(10);const Apple b(3);b.add(100);return 0;}
编译: g++ -o main main.cpp apple.cpp
结果:
getCount const2take func const2add func const2take func const22add func 10take func const10add func const100take func const100
上面getCount()方法中调用了一个add0方法,而add方法并非const修饰,所以运行报错。也就是说const对象只能访问const成员函数。
而add方法又调用了const修饰的take方法,证明了非const对象可以访问任意的成员函数,包括const成员函数。
除此之外,我们也看到add的一个重载函数,也输出了两个结果,说明const对象默认调用const成员函数。
我们除了上述的初始化const常量用初始化列表方式外,也可以通过下面方法:
第一:将常量定义与static结合,也就是:
static const int apple_number
第二:在外面初始化:
const int Apple::apple_number=10;
当然,如果你使用c++11进行编译,直接可以在定义出初始化,可以直接写成:
static const int apple_number=10;// 或者const int apple_number=10;
这两种都在c++11中支持!
编译的时候加上-std=c++11即可!
这里提到了static,下面简单的说一下:
在C++中,static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现文件中初始化。
在类中声明:
static int ap;
在类实现文件中使用:
int Apple::ap=666
对于此项,c++11不能进行声明并初始化,也就是上述使用方法。
