Const关键字 C/C++/Java

45 篇文章 1 订阅
9 篇文章 1 订阅

const关键字是永恒不变的意思,用它修饰的关键字只具有度的特性,没有办法进行写操作。const常变量只在编译期有用,在运行期无用,可以很好的增加程序的健壮性,防止一些不必要的变量被错误修改引发的程序问题。const修饰的变量是只读的,本质还是变量。

现代C编译器(如Vc、gcc)中的const将具有全局生命周期(如全局变量,static属性的变量)存储于只读存储区,修改该变量时将导致程序崩溃。【注意】标准C语言编译器(如bcc)不会被const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,其值依然可以改变。

1. C/C++面向过程

1.1 面向过程中const关键字主要可以用来

(1)定义常量,和define语句类似。但是相比较而言,使用const在很多编译器中是不会给分配空间的,这样可以大大减少内存的使用量。

(2)指针和常量。在使用指针时,需要确定的一个事情是指针本省还是被它指定的对象。讲一个指针的声明使用const预先固定下来,将使得这个对象而不是这个指针称为常量,这个是后不能使用*来修改指针只想地址空间的内容。如果我们限制指针本身不被修改,这个时候必须声明运算法*const。

(3)const修饰函数入参。函数内部不能修改入参值,一般情况下用于指针,这样可以保证入参数据的安全性。

(4)函数返回值。参数可以直接赋值给一个常量或者指针。const修饰函数返回值表示返回值不可改变,多用于返回指针的情形。

#include <iostream>
using namespace std;

const int func1(const int var1, int var2)			// 函数返回值不可修改
{
//	var1 = 10; Error, 不能修改
	var2 = 10;
	printf("Func parameter const int %d, int %d\n", var1, var2);

	return var2;
}

extern const int global1 = 10;
const int global2 = 10;

int main(int argc, int** argv)
{
	const int MAX_CHAR = 60;
	int const MAX_ARRAY = 30;

	const char hello[MAX_CHAR] = "Hello World!";
	char const name[MAX_CHAR] = "Eric Hao";

	printf("Main const int %d, const char hello %s, const char name %s\n", MAX_CHAR, hello, name);

	const int array_int[MAX_ARRAY] = { 0, 1 };
	printf("Const array int %d, context %d\n", MAX_ARRAY, array_int[0]);

	int const_point0 = 21;
	int const_point1 = 11;
	int* const p_int_const = &const_point0;
	printf("const point0 %d, const point1 %d p_int_Const %d\n", const_point0, const_point1, *p_int_const);
	// p_int_const = &const_point1; 表达式必须是可修改的左值
	const_point0 = 23; // const指针不能被修改指定另外一个地址,但是已经指定的这个位置可以通过变量来直接修改,对应内容也修改了
	printf("const point0 %d, const point1 %d p_int_Const %d\n", const_point0, const_point1, *p_int_const);
	*p_int_const = 24;
	printf("const point0 %d, const point1 %d p_int_Const %d\n", const_point0, const_point1, *p_int_const);

	// int* const p_int = &MAX_CHAR; const int* 不能初始化 int *const类型实体
	int int_const_point0 = 30;
	int int_const_point1 = 31;
	const int *p_const_int = &int_const_point0;
	printf("Const int point0 %d, point1 %d, p_const_int %d\n", int_const_point0, int_const_point1, *p_const_int);
	p_const_int = &int_const_point1;
	printf("Const int point0 %d, point1 %d, p_const_int %d\n", int_const_point0, int_const_point1, *p_const_int);
	// *p_const_int = 32; 错误,也就是说这个指定指针是可变的,但是指定的内容是不可变的,也就是内容不能通过*来修改
	int_const_point1 = 32;
	printf("Const int point0 %d, point1 %d, p_const_int %d\n", int_const_point0, int_const_point1, *p_const_int);
	// *p_const_int = 32; 错误,也就是说这个指定指针是可变的,但是指定的内容是不可变的,也就是内容不能通过*来修改

	system("pause");
	return 0;
}

1.2. const VS define

很多人在学习 const 的时候都会混淆它与 define 的区别。从功能上说它们确实很像,但它们又有明显的不同:

  1. define是预编译指令,而const是普通变量的定义。define定义的宏是在预处理阶段展开的,而const定义的只读变量是在编译运行阶段使用的。
  2. const定义的是变量,而define定义的是常量。define定义的宏在编译后就不存在了,它不占用内存,因为它不是变量,系统只会给变量分配内存。但const定义的常变量本质上仍然是一个变量,具有变量的基本属性,有类型、占用存储单元。可以说,常变量是有名字的不变量,而常量是没有名字的。有名字就便于在程序中被引用,所以从使用的角度看,除了不能作为数组的长度,用const定义的常变量具有宏的优点,而且使用更方便。所以编程时在使用const和define都可以的情况下尽量使用常变量来取代宏。
  3. const定义的是变量,而宏定义的是常量,所以const定义的对象有数据类型,而宏定义的对象没有数据类型。所以编译器可以对前者进行类型安全检查,而对后者只是机械地进行字符替换,没有类型安全检查。这样就很容易出问题,即“边际问题”或者说是“括号问题”。

2. C++面向对象特性

在C++面向对象中首先涉及的是函数参数引用&形式,这表示这个函数内部是没有办法通过修改对应的值类进行函数参数返回。当然一般情况下对入参const限制本省就是放置这个参数引用被以外修改。对于函数返回值使用的,const限制以后和正常的返回值的函数被const限制一样的道理,可以被复制给一个具体的const修饰的应用。但是这里要强调的一点是,在函数返回如果是局部变量的情况下(虽然这种情况是代码错误),这个时候如果使用const进行限制,这个值还是可以被保留下来正常返回的。

2.1 const修饰类成员函数

(1)const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数;
(2)const对象的成员是不能修改的,而通过指针维护的对象确实可以修改的;
(3)const成员函数不可以修改对象的数据,不管对象是否具有const性质。编译时以是否修改成员数据为依据进行检查。这种类型的函数一般情况下只能用来获取数据或者是进行数据打印等操作。

#include <iostream>
using namespace std;

class CConst{
public:
	CConst(int a) :m_constInt(a) {};
	const int getConstValue(void) const
	{
		// m_constInt = 20; 表达式是可修改的左值,返回错误信息
		printf( "Class get const value %d\n", m_constInt );
		return m_constInt;
	}
private:
	const int m_constInt = 0;
	int m_int = 10;
};

int main(int argc, int** argv)
{
	CConst mconst(10);
	mconst.getConstValue();

	system("pause");
	return 0;
}

const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。如

class A

{

 const int size = 100;    //错误

 int array[size];         //错误,未知的size

}
const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。如

class A

{…

 enum {size1=100, size2 = 200 };

int array1[size1];

int array2[size2];

}

枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

在面向的C++中,如果是需要使用#define定义的常数类型量,一般情况下都用const替代,主要原因是define关键字破坏了面向对象域和类型的封装的特性,打破了访问界限。

先初步了解引用、指针的一些注意事项。

  • 引用并非对象
  • 引用必须初始化
  • 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起
  • 类型要严格匹配
int &a = 10;             //错误:引用类型的初始值必须是一个对象  
  
double a = 3.14;  
int &b = a;              //错误:此处引用类型的初始值必须是int型对象

指针本身就是对象

指针的类型要和它指向的对象严格匹配

double dval;  
double *pd = &dval;      //正确  
double *pd2 = pd;        //正确  
  
int *pi = pd;            //错误:指针pi的类型和pd的类型不匹配  
pi = &dval;              //错误:试图把double型对象的地址赋给int型指针  

有例外:引入const 限定符

常量引用

初始化常量引用时允许用任意表达式作为初始值

int i = 42;  
const int &r1 = i;       //正确:允许将const int & 绑定到一个普通int对象上  
const int &r2 = 42;      //正确  
const int &r3 = r1 * 2;  //正确  
int &r4 = r1 * 2;        //错误  
  
double dval = 3.14;  
const int &ri = dval;    //正确  
//等价于  
const int temp = dval;  
const int &ri = temp;  
  
int i = 42;  
int &r1 = i;  
const int &r2 = i;  
r1 = 0;                  //正确  
r2 = 0;                  //错误  

2.2. 使用const的一些建议

1) 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2) 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3) 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4) const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5) 不要轻易的将函数的返回值类型定为const;
6) 除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

3 考点

3.1. 指针常亮和常亮指针

详细见指针(一)章节

4. Java中final替代const

1.final修饰变量

final成员变量表示常量,只能被赋值一次,赋值后值不再改变。final经常和static一起使用表示常量(即static final,不用实例化)。

2.final修饰方法

final方法表示不能被子类重写,但可以被继承,如果认为一个方法的功能足够完善,子类不需要改变的话,就声明为final。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。

重写(覆盖):在子类中定义某方法与其父类有相同的名称,返回类型和参数(有继承关系)

重载:JAVA中一个类可以有多个同名方法,参数类型或个数等可以不同。(没有继承关系)

3.final修饰类

final类功能通常是完整的,它们不能被继承,没有子类,Java中有许多类是final的,譬如String, Interger以及其他包装类。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值