C++基础复习提升-const那些事
- 1.1其他文件中调用(是/非)const定义的常量
- 1.2const定义的常量必须要赋初始值
- 1.3常量指针
- 1.4使用const void*指针保存const对象的地址
- 1.5将非const对象的地址赋给const对象的指针
- 1.6指向常量的指针通过非const对象指针改变const对象指针指向的地址的值
- 1.7常指针
- 1.8常指针指向常量地址和变量地址
- 1.9常指针传参
- 1.10函数里传const对象引用提高效率和防止修改
- 1.11类中const成员函数只能访问和操作const成员函数,不能操作(常/非常)成员变量但可以访问,非const对象可以访问任意成员函数,const对象不能访问操作非const函数,但是可以访问非const变量,可以操作static修饰的非const变量和函数
参考C++那些事-光城大佬的网站
下一篇C++基础复习提升-static那些事
1.1其他文件中调用(是/非)const定义的常量
其他文件调用const修饰的常量,需要借助extern关键字,非const修饰的常量则不需要在定义文件中使用extern关键字修饰也可调用。函数调用也是同理。
file1.txt定义
extern const int a = 100;
int b = 200;
file2.txt调用
extern const int a;
extern int b;
1.2const定义的常量必须要赋初始值
const定义的常量必须赋初始值,因为常量在定义后不能修改,所以定义时必须初始化。
1.3常量指针
常量指针指针的值不能改变
const int *ptr;
由于指针ptr指向的是const对象定义的int类型(也就是指向int类型的某块地址),const定义的是int类型的常量,而不是指针ptr本身,所以ptr可以不用赋初始值,但是不能通过ptr去修改所指对象的值。error写法:*ptr=10;
1.4使用const void*指针保存const对象的地址
注意不能使用void *指针来保存const对象的地址
const int p = 10;
const void *x = &p;
// 强转
const int *q = (const int*)x;
1.5将非const对象的地址赋给const对象的指针
const int *ptr;
int val;
ptr = &val;
1.6指向常量的指针通过非const对象指针改变const对象指针指向的地址的值
// ptr指向int类型的const对象
const int *ptr;
// ext_value:10,ptr指向ext的地址
ptr = &ext;
// 打印ptr指向地址的值
cout << *ptr << endl;
// ptr1也指向ext的地址
int *ptr1 = &ext;
// 通过非const对象指针改变ext的值,从而改变ptr指向的值
*ptr1 = 29;
cout << *ptr << endl;
1.7常指针
常指针必须要赋初值,并且const指针的值不能改变(也就是指向的地址不能改变),但是指针ptr指向地址的值是可以变化的。
// 指针常量(常指针)必须要赋初始值,且const指针指向的地址不能改变
int *const ptr = &ext;
*ptr = 200;
1.8常指针指向常量地址和变量地址
const int num = 110;
// 错误写法:int *const ptr = #
// 上述错误原因是因为ptr是一个const指针指向了一个int类型的地址,指向的是一个变量地址,而不是一个const常量地址
// 正确写法
const int *const ptr = #
1.9常指针传参
void func(int *const val, const int *val2) {
// 由于是常指针,所以const指针指向的地址不能变,但是指向的地址的值可以改变
// 若要对实参进行保护,则传指针的常量参数,使之在函数中无法对实参进行修改
*val = 109;
val2 = val;
cout << *val2 << endl;
}
int main() {
// exp:10
cout << exp << endl;
// 传的是引用,改变形参影响实参
func(&exp, &exp2);
// exp:109
cout << exp << endl;
return 0;
}
1.10函数里传const对象引用提高效率和防止修改
void test(const A&a);
若使用引用效率低的原因是函数体首先会在内部产生A类型的临时对象用于复制参数a,这一过程就需要对临时对象进行构造,复制和析构,这将消耗大量时间。而引用传递仅仅是借用一下参数的别名,不会产生临时对象。
若参数是是非对象传递而不是对象传递,则不需要使用引用,采用值传递的形式,因为值传递不存在构造,析构的过程,复制也非常快,值传递和引用传递的效率相差无几,这种情况使用引用传递则会增加代码可读性的难度。
1.11类中const成员函数只能访问和操作const成员函数,不能操作(常/非常)成员变量但可以访问,非const对象可以访问任意成员函数,const对象不能访问操作非const函数,但是可以访问非const变量,可以操作static修饰的非const变量和函数
// file apple.cpp
using namespace std;
class Apple {
private:
int people[100];
int a = 120;
int const b = 20;
public:
Apple(int i);
const int apple_number;
void take(int num) const;
int add(int num);
int add(int num) const;
void nonConstFunction();
int getCount() const;
};
// file main.cpp
#include <iostream>
#include "apple.cpp"
using namespace std;
Apple::Apple(int i) : apple_number(i) {}
// 非const成员函数
int Apple::add(int num) {
take(num);
// correct: a = 20;非const成员函数可以对成员变量进行修改
return num;
}
//const成员函数(常成员函数),提高程序的健壮性
int Apple::add(int num) const {
take(num);
//error:a = 300; const成员函数不能对成员变量进行修改
return num + 1;
}
void Apple::nonConstFunction() { cout << "this is a non_const test file" << endl; }
void Apple::take(int num) const {
cout << "take func:" << num << endl;
}
// 常函数只能访问常函数,不能访问非常函数,不能修改(非常/常)成员变量
int Apple::getCount() const {
take(1);
add(100);
//error:a = 20; a是非常成员变量
printf("apple_num:");
return apple_number;
}
int main() {
Apple a(2);
cout << "get_count():" << a.getCount() << endl;
// 非 常对象可以访问常成员函数,若没有重载非const函数add,则调用常函数add
cout << "a.add():" << a.add(10) << endl;
cout << "a.non_const():" << " ";
a.nonConstFunction();
cout << "--------------------------------------------" << endl;
const Apple b(3);
// 常对象只能操作常成员函数
// 不能访问非const函数,error:例如b.nonConstFunction()是错误的
cout << "b.getCount():" << b.getCount() << endl;
cout << "b.add():" << b.add(110) << endl;
return 0;
}