C/C++中的const

2,438 阅读5分钟

1、C中的const

  • 1、局部const变量存放在堆栈区中,会分配内存(也就是说可以通过地址间接修改变量的值)。测试代码如下:
void main()
{
 const int a = 10;
 printf("initial a = %d\n", a);
 int *ptr = &a;
 *ptr = 100;
 printf("modify a = %d\n", a);
}

运行结果:

  • 2、全局const变量存放在只读数据段(不能通过地址修改,会发生写入错误), 默认为外部联编,可以给其他源文件使用(需要用extern关键字修饰)
const int a = 10;
//不能用变量初始化全局const变量,编译器不通过:表达式必须含有常量值
//const int b = a; 
void main()
{
	printf("first a = %d\n", a);
	int *ptr = &a;
	//编译器通过,但运行阶段发生写入错误
	*ptr = 100;
	printf("second a = %d\n", a);
}

运行结果:

由于分文件编写,不好呈现,所以在这里不为大家提供c语言全局const变量默认为外部联编的案例。如果各读者有兴趣,可自行尝试。具体步骤如下,可新建一个源文件,并且提供a变量的声明,如:extern const int a。

2、C++中的const

  • 1、普通局部const变量

对于基本类型,以符号表中的数据进行初始化的普通局部const变量,此时不会分配内存,将其放入符号表中,如果对它取地址,则会开辟一个新的空间,也就是说会创建一个临时变量,如果通过地址间接进行修改值不会影响到其本身。测试代码如下:

	const int a = 10;
	int *ptr = const_cast<int*>(&a);
	*ptr = 100;
	cout <<"a = "<<a << endl;
	cout <<"*ptr = "<<*ptr << endl;

运行结果:

在这里解释一下上述代码:第二行代码,使用了const(expression),显示转换,这是由于c++比c类型转换更严格。所以需要将 const int * 转换为 int * 才能够进行赋值,并且第二行代码将被隐式转换为如下代码:

    int temp=a;
    int *ptr=&temp;
    //所以对指针 ptr 指向的内存空间进行操作,并不会影响到 a。

对于基本类型,用变量初始化的普通局部const变量,此时会在堆栈区开辟内存,可以通过地址间接修改值。测试代码如下:

	int b = 10;
	const int a = b;
	int *ptr = const_cast<int*>(&a);
	*ptr = 100;
	cout << "a = " << a << endl;
	cout << "b = " << a << endl;
	cout << "*ptr = " << *ptr << endl;

运行结果:

(3)对于自定义类型,都会分配内存,可以通过地址间接修改值

class Person
{
public:
	Person(int age) { this->age = age; };
	~Person() {};
	int age;
private:
};
int main()
{
	const Person personA(20);
	Person* personPtr = const_cast<Person *>(&personA);
	personPtr->age = 100;
	cout <<"personPtr->age = "<<personPtr->age << endl;
}

运行结果:

  • 2、普通全局const变量

    • 与局部const变量基本相同,只是内存开辟在全局/堆区,对于c++而言,全局const变量默认为内部联编,可以在定义时加extern关键字声明为外部联编。 由于分文件编写不好展示,请读者自行尝试。
  • 3、const 成员变量/成员函数

    • const成员变量只能被const成员函数访问

    • const成员函数,能够访问所有成员变量,但是在函数体内不能直接修改变量的值(包括普通成员变量),如果需要在函数体内修改普通成员变量的值,需要在变量定义的前面添加mutable关键字,或者通过地址间接修改。注意:const成员函数只能被该类的const对象访问。测试代码如下:

class Person
{
public:
	Person() {};
	~Person() {};
	void test()const
	{
		//没有加mutable修饰的变量在const成员函数内不能直接修改
		//b = 20;
		//可以通过地址间接修改
		int* Bptr = const_cast<int*>(&b);
		*Bptr = 1000;
		//使用mutable修饰的变量可以通过
		c = 30;
		cout << b << endl;
		cout << c << endl;
	}
private:
	const int a=10;
	int b = 100;
	mutable int c = 20;
};
int main()
{
	Person p;
	p.test();
	return 0;
}

运行结果:

3、C/C++中const异同总结

  • c语言全局const会被存储到只读数据段。c++中全局const当声明extern或者对变量取地址时,编译器会分配存储地址,变量存储在只读数据段。两个都受到了只读数据段的保护,不可修改。

  • c语言中局部const存储在堆栈区,只是不能通过变量直接修改const只读变量的值,但是可以跳过编译器的检查,通过指针间接修改const值。

  • c++中对于局部的const变量要区别对待:

    • (1)对于基础数据类型,也就是const int a = 10这种,编译器会把它放到符号表中,不分配内存,当对其取地址时,会分配内存。 a在符号表中,当我们对a取地址,这个时候为a分配了新的空间,*p操作的是分配的空间,而a是 从符号表获得的值。

    • (2)对于基础数据类型,如果用一个变量初始化const变量,如果const int a = b,那么也是会给a分配内存。

    • (3)对于自定数据类型,比如类对象,也会分配内存。

  • c中const默认为外部连接,c++中const默认为内部连接.当c语言两个文件中都有const int a的时候,编译器会报重定义的错误。而在c++中,则不会,因为c++中的const默认是内部连接的。如果想让c++中的const具有外部连接,必须显示声明为: extern const int a = 10;