C++const总结(出现在不同地方)

本文详细解析了C++中的const关键字,包括其在函数参数、返回值和成员函数中的用法,以及如何正确使用const引用、const对象的动态数组和const形参。同时,通过实例代码展示了如何在实际编程中应用const关键字,以保护数据不被意外修改,提高代码的健壮性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

const int *const method(const int *const &param) const;
  1          2            3          4             5

1:const int

常量整型(值不能被修改)

2:*const

常量指针(指向的对象不能被修改)

1和2结合起来:const int *const method();

返回指向常量整型的常量指针。

3:同1

4:同2

3和4结合起来:const int *const &param

形参为指向 指向常量整型的常量指针的 引用。

5:method() const;

调用该方法,不会改变该类内部非 mutable 成员。

从 const 成员函数返回 *this。在普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针。在 const 成员函数中,this 的类型是一个指向 const 类类型对象的 const 指针。(C++ Primer 中文第四版 P377)

 ==============================================================================================

其他关于 const 的知识点:

1、非 const 变量默认为 extern。要使 const 变量能够在其他的文件中访问,必须显示地指定它为 extern。

2、const 引用:指向 const 对象的引用。非 const 引用只能绑定到与该引用同类型的对象。const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

3、const 对象的动态数组。如果我们在自由存储区中创建的数组存储了内置类型的 const 对象,则必须为这个数组提供初始化:

// 内置类型
const int *pci_ok = new const int [100]();
// 类类型必须提供默认构造函数
const string *pcs = new const string[100];

 4、const 形参。如果函数使用非引用的非 const 的形参,则既可以给函数传递 const 实参也可以传递非 const 的实参。如果形参为非引用的 const 形参,则在函数中,不可以改变实参的局部副本。但传递的实参的形式同之前一样。

 5、对于

void fcn(const int i) {}
void fcn(int i) {}

编译器认为 fcn(int i) 重定义,这是为了兼容C。

 6、如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为 const 引用。

 7、应该将不需要修改的引用形参定义为 const 引用。普通的非 const 引用形参在使用时不太灵活。这样的形参既不能用 const 对象初始化,也不能用字面值或产生右值的表达式实参初始化。

 ==============================================================================================

对于读含有 const 的表达式的技巧:从右往左读。

一般形式为“类型 + const”或者“* + const”形式,对于表达式首的 const 一般可以把“const + 类型”转成“类型 + const”。


例子:

#include <iostream>
using namespace std;

//int const* func(const int&) | const int* func(const int&) | int *func() const区别
//const一般有三种用处:修饰函数参数;修饰函数返回值;const成员函数。
//如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有任何价值
//(第一没有起到保护作用,第二没有起到提高效率的作用)。因为外部临时变量在使用之后就会消失了,
//所以加const就没有意义,而如果传的是地址,那么当函数结束后还是可以通过地址对原来函数里保存在堆上的变量进行操作

const int* func(const int& a){
 //a++; //这样就保护了传入的指针指向的内容不被修改
 //这样对于返回一个关键内存位置的内容很有意义,起到只能访问而不被恶意修改的作用
 //另外,使用const&一方面出于保护目的,另一方面还有提高效率,省略临时对象,不必调用构造函数的好处。
 //但是必须分清楚,要用到的究竟是一个对象的“拷贝”还是仅返回“别名”!!!
 return &a;
}

class Stack{
public:
 //const函数,不能修改类成员变量,不能调用非const函数(必须是显示指明的const函数)。
 void push()const;
 int pop();
 int getcount()const;
private:
 int m_num;
 int m_data[100];
};
void Stack::push()const{}
int Stack::pop(){
 return m_num;
}
int Stack::getcount() const{
 push();
 //m_num=m_num+1;
 //pop();
 cout << m_num << endl;
 return m_num;
}

int main()
{
 const int *pFunc2;
 pFunc2=func(para);
 cout << *pFunc2 << endl;
 pFunc2++;
 //(*pFunc2)++;  //这样就保护了返回指针指向的内容不被修改
 //这样对于返回一个关键内存位置的内容很有意义,起到只能访问而不被恶意修改的作用

 //非const对象可以访问const和非const成员函数
 Stack s1;
 s1.pop();
 s1.getcount();
 //cosnt对象只可以访问const成员函数
 const Stack s2;
 //s2.pop();
 s2.getcount();

 return 0;
}

 

#include<iostream>

using namespace std;

// Ahthor:	过往记忆
// E-mail:	wyphao.2007@163.com
// Blog:	http://www.iteblog.com
// 转载请注明出处

class TestClass {
public:
	size_t length() const;
	const char* getPContent();
	void setLengthValid(bool isLengthValid);
private:
	char *pContent;
 	size_t contentLength; 	 	//A
 	bool lengthIsValid; 	 	//B
 	size_t precontentLength;
};

size_t TestClass::length() const{ //函数名后加const
	if(!lengthIsValid){
		contentLength= strlen(pContent); 	//C
		lengthIsValid = true; 	 	 	//D
	}

	return contentLength;
}

const char* TestClass::getPContent(){//函数名前加const
	return pContent;
}

void TestClass::setLengthValid(bool isLengthValid){
	lengthIsValid = isLengthValid;
}

int main(void){
	TestClass *tc =new TestClass;
	tc->setLengthValid(false);
	tc->length();
	char * content = tc->getPContent(); 	 	//E
	return 0;
}
其中类TestClass中的length函数和getPContent函数分别在函数名后和前加了const修饰符,如果试图编译上面的代码,将会得到下面的错误:

--------------------配置: mingw5 - CUI Debug, 编译器类型: MinGW--------------------
检查文件依赖性...
正在编译 C:\Users\wyp\Desktop\未命名1.cpp...
[Error] C:\Users\wyp\Desktop\未命名1.cpp:24: error: assignment of data-member `TestClass::contentLength' in read-only structure
[Error] C:\Users\wyp\Desktop\未命名1.cpp:25: error: assignment of data-member `TestClass::lengthIsValid' in read-only structure
[Error] C:\Users\wyp\Desktop\未命名1.cpp:43: error: invalid conversion from `const char*' to `char*'
[Warning] C:\Users\wyp\Desktop\未命名1.cpp:45:2: warning: no newline at end of file

构建中止 未命名1: 3 个错误, 1 个警告

里面有三个错误,也就是代码C、D、E处的三个地方。为什么C和D处的代码会出错,原因如下
length函数名的后面加了const修饰符,这样说明函数的成员对象是不允许修改的。我们都知道,在类的成员函数里面,默认是在成员函数的第一个位置是this指针,如果在成员函数(只能是成员函数,要是类的静态函数或者是非成员函数就不可以在函数名后面加上const)后面const,则说明this指针的值是不可以修改的,只能读取。而上面的length函数可能会修改里面的contentLength和lengthIsValid的值,这样编译器肯定是不允许的,所以这样是会出现错误的。
解决方法是:在类的A、B处的成员前面加上mutable修饰符:

1 mutable size_t contentLength;   //A
2 mutable bool lengthIsValid;     //B

从字面的意思知道,mutalbe是“可变的,易变的”,跟constant(既C++中的const)是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。这样在C、D处将不会出错。
那么,为什么E处出现了错误。这是因为在函数名getPContent前加了const修饰符,意味着该函数返回的值只能是读取,而不能被修改。而E处的content却为char *是可以被修改的,这与const正好相反了,所以出现了错误。解决方法是:在char *前面加上const修饰符,即:

1 const char * content = tc->getPContent(); //E

再去编译运行,这样就不会出现错误了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值