我正在读一本名为“Effective C ++,Second Edition”的书,以及它关于const成员函数的讨论,以及你如何具有逐位的概念和概念常数。
它说大多数编译器都会使用按位常量,这是因为你无法改变const成员函数内对象的数据成员。
然后有一个成员函数的例子似乎在const测试中没有按位。
它是这样的:
#include "stdafx.h"
#include <string>
#include <iostream.h>
using namespace std;
class mystring
{
public:
mystring(const char* value);
operator char *() const { return data; }
private:
char * data;
};
mystring::mystring(const char * value)
{
mystring::data = const_cast<char*>(value);
}
int main(int argc, char* argv[])
{
const mystring s = "Hello";
char * nasty = s;
*nasty = 'M';
printf("s: %c", s);
return 0;
}
运行此功能时,它会在我的书中说明它应该允许您更改s
的值,即使它是const
。这是因为char *数据指向与const char*
值指向的相同。在这种情况下,*data
不是const
。
但是尝试在MS VC ++ 6.0中运行它,它会在行*nasty = 'M';
处抛出访问冲突
有人可以解释发生了什么吗?我想我错过了什么?
对我来说,似乎因为我们有一个const mystring s
,我们不应该改变它,但是它在书中所说的内容似乎很尴尬。
答案 0 :(得分:7)
访问冲突是因为您尝试更改字符串文字。您的代码相当于:
char * p = "Hello";
* p = 'M';
在C和C ++中都是非法的 - 与const成员函数无关。
答案 1 :(得分:2)
您只能获得访问冲突,因为char*
指针是字符串文字。更改字符串文字是未定义的行为(在您的情况下为AV),它与const-correctness无关。
答案 2 :(得分:0)
您正在做的是未定义的行为。您正在抛弃常量并尝试修改常量值。如果该例子已经从书中原样复制,那么这本书是错误的。
与const_cast<>
合法的是将constness从常量指针/引用转移到非const对象:
int i = 5;
int const & ir = i;
const_cast<int&>(ir) = 7; // valid
int const * ip = &i;
*const_cast<int*>(ip) = 9; // valid
const int c = 11;
int const & cr = c;
const_cast<int&>(cr) = 13; // Undefined behavior
你无法从对真正的const对象的引用中抛弃const的原因是编译器可以决定将对象放在只读内存中,在这种情况下,操作可能以不同的方式失败(杀死应用,忽略变化......)
答案 3 :(得分:0)
在您的示例中,您不会更改s
,而是尝试更改成员变量s
指向的内存。由于您被允许在许多地方放置const
,因此您必须小心实际声明const
。
您的成员函数operator char*() const
不允许更改任何成员变量。尝试operator char *() const { data = "something else"; return data; }
,您的编译器会告诉您不允许修改data
。但是,在这种情况下,您只需返回data
而无需修改。这是允许的。您甚至可以更改data
指向的内存,如operator char *() const { *data = 'M'; return data; }
中所示。但是,由于data
指向不允许更改的字符串文字,因此在您的上下文中失败。