const修饰符¶
例一 经典的char* pchar = "xxx"¶
C中最常见的一个问题-char* pchar = "xxx"的隐含了什么,算是C语言的一个坑,也算是语法要求不严谨。如下:
void testConstChar()
{
char* pchar = "abc";
pchar[1] = 'a';
}
函数``testConstChar``执行结果是什么样的?为什么? 从字面上看char* pchar = "abc";只是定义子一个指向字符串的指针;而实际 上pchar的类型应该是: const static char*。即:pchar隐含 了const属性,修改pchar指向的内存必然引发’segment fault’。
在C编译器中完全没有任何提示警告;C++编译器会警告:deprecated conversion from string constant to ‘char*’
另外如果将上面的变量pchar声明为: char pchar[] = “abc”;则表示pchar是一个字符数组。
例二 对返回值的影响¶
对例一进行一下扩展延伸,定义下面这样一个类及其成员函数:
class cTestConstChar
{
public:
const char* GetChar()
{
char* pChar = "hello world!";
return pChar;
}
};
void testConst()
{
cTestConstChar c;
std::cout << c.GetChar() << std::endl;
}
上面的函数运行结果是怎么样的?为什么?
一眼看去cTestConstChar::GetChar()返回了一个局部指针变量,将引发未知结果。
回想一下例一,可以知道,局部变量pChar实际类型是: const static char*,即:它指向的内存区域不会因为函数返回而被释放,所以cTestConstChar::GetChar()将会返回一个正确可用的,指向字符串”hello world!”的地址。将会正常输出”hello world!”。
Note
再推广一下:函数可以返回局部的static变量的地址或引用。(但是好像没有 人推荐这种用法:))
例三 修改const变量值¶
const修饰的变量,其值是不可以修改的,但是可以通过方法去掉const属 性,这样就可以修改了,看看下面这个例子的:
void testChangeConstValue()
{
const int nValue = 10;
int* pInt = const_cast<int*>(&nValue);
*pInt = 100;
std::cout << *pInt << ", " << nValue << std::endl;
}
函数``testChangeConstValue``的输出会是什么?为什么?
为什么? 1. 常量的值不可改变?那么const_cast是干什么用的? 2. const_cast分配的一块新的内存空间来保存nValue的值? 3. ...
通过断点逐步调试看看
调试会发现: pInt确实指向了nValue的内存地址,而且修改了内存值,那么 为什么nValue的输入结果依然是10呢?
推测应该是编译器在编译时直接将nValue替换为了10, 在调用cout时没有去读内存值。查看 汇编代码可以确认。
Note
非绝对必要,还要修改const变量的值,即使修改也要仔细考虑,调整代码, 注意编译器的优化。
例四 类的const成员函数¶
类的const成员函数不能修改类的成员变量,看一下下面这个例子:
class cTestConstMember
{
public:
cTestConstMember();
~cTestConstMember();
void DoThings() const;
private:
int m_nCount;
mutable int m_nMutable;
int* m_pInt;
};
cTestConstMember::cTestConstMember()
: m_nCount(10)
, m_nMutable(1)
, m_pInt(nullptr)
{
m_pInt = new int(100);
}
cTestConstMember::~cTestConstMember()
{
if (nullptr != m_pInt) {
delete m_pInt;
m_pInt = nullptr;
}
}
void cTestConstMember::DoThings() const
{
std::cout << "Test Class Const Member Function" << std::endl;
std::cout << m_nCount << ", " << m_nMutable << ", " << *m_pInt << std::endl;
// 妄图修改类成员变量,编译都无法通过
// m_nCount = 100;
m_nMutable = 11;
*m_pInt = 10;
std::cout << m_nCount << ", " << m_nMutable << ", " << *m_pInt << std::endl;
}
void TestConstMember()
{
/*const */cTestConstMember c;
c.DoThings();
}
这个例子就不细说了,在上面使用了关键字mutable,mutable修饰的变量 不受对象的const修饰符的影响,可以被修改。