【问题标题】:const and no const methods in c++?c++ 中的 const 和没有 const 方法?
【发布时间】:2010-10-15 15:21:05
【问题描述】:
我有一个程序,它的许多类都有一些带有关键字 const 的运算符和方法,如下所示:
operator const char* () const;
operator char* ();
void Save(const char *name) const;
void Load(const char *name);
首先:方法声明末尾的const是什么意思?,和放在开头一样吗?
第二:为什么需要 const 版本和无 const 版本的 operator()?
提前致谢。
【问题讨论】:
标签:
c++
const-correctness
【解决方案1】:
首先:方法声明末尾的const是什么意思?,和放在开头一样吗?
没有。末尾的const 意味着可以在声明为const 的对象上调用该方法。开头的const表示返回值为const。
第二:为什么需要 const 版本和无 const 版本的 operator()?
非常量版本返回一个char*,它不是常量。通过修改 char*,您实际上可以修改对象(假设 char* 是对象的成员)。
由于 const 对象不允许这样做,因此对于 const 对象有 operator() 的重载,因此会返回 const char*,因此无法通过它修改对象。
【解决方案2】:
'const' 告诉编译器这个方法不会改变任何成员变量——在 const 实例上调用这个方法是安全的。因此,可以在 const 实例上调用 Save,因为它不会更改该实例。另一方面,加载会改变实例,因此不能用于 const 实例。
operator() 的 const 版本传回一个 const 指针,保证传回的缓冲区不会改变。大概这是指向该类的实例变量的指针。对于非常量实例,另一个 operator() 传回一个非常量指针。它必须是指向某些内存的指针,即使写入也不会改变实例的内容。
另外,有时查找“可变”关键字。理解这一点将有助于您理解这种 const-correctness 的概念。
【解决方案3】:
成员函数常量。这意味着该函数不能(*)修改您的任何成员变量。这就像在这个函数调用的所有成员变量前面放置一个 const。这对您的类的客户来说是一个很好的保证,也可能有助于编译器优化。
(*) - 另见关键字 mutable。
【解决方案4】:
将const 放在方法声明的末尾表示对象本身或this 是const,而不是返回类型。
出于复杂的原因,C++ 允许在 const 上重载方法。这里没有足够的空间来详细介绍。但这里有几个简短的。
- 有时,当从
const 类型调用一个方法时,它的行为会有所不同,这是有价值的,或者说是绝对必要的。最直接的示例是,当您希望从 const 方法返回 const 值并从普通方法返回非常量值时。
-
this 是否为const 会极大地改变内部方法的绑定。以至于它本质上将成为两个不同的方法体。因此,将其分解为两种不同的方法是有意义的。
【解决方案5】:
除了其他答案之外还有一个注意事项:您的示例中没有 operator()。
operator const char* () const;
operator char* ();
是转换运算符,这意味着类的对象可以隐式转换为C风格的字符串,如
void f(const MyClass& x, MyClass& y) {
const char* x_str = x;
char* y_str = y;
}
operator() 的声明和用法,这意味着您可以使用类似于函数的类类型的对象,如下所示:
class MyClass {
public:
const char* operator() (int x, int y) const;
// ...
};
void g(const MyClass& obj) {
const char* result = obj(3, 4);
}
【解决方案6】:
如果您正在寻找有关 C++ 的优秀资源(包括正确使用 const 的提示),请尝试“Effective C++”。
一个有用的网站:JRiddel.org
在 C++ 中,当您通过将方法 const 放在方法签名之后声明方法时,您断言“此方法不会更改正在调用它的对象中的任何非mutable 实例变量。”
返回值之前的const(例如:operator const char*..." 中的常量)声明它只返回一个指向const char* 的变量指针。 (您可能无法更改char* 的内容,但您可以重新分配指针。)如果您写“const char* const ...”,它将是一个指向常量字符的常量指针。 (const 在星号之后)。
多个版本很有用,因此编译器可以理解这一点:
const char* my_const_var = <object_name>();
char* my_var = <object_name>();
克里斯
【解决方案7】:
你应该参考“HIGH·INTEGRITY C++ CODING STANDARD MANUAL”了解何时建议对类成员使用const修饰符:
高完整性 CPP 规则 3.1.8:声明“const”任何不修改对象外部可见状态的类成员函数。 (QACPP 4211, 4214)
理由:尽管语言强制执行按位 const 正确性,但 const 正确性应该被认为是逻辑的,而不是按位的。如果客户端无法确定对象是否由于调用该函数而发生更改,则应将成员函数声明为 const。 'mutable' 关键字可用于声明可在 const 函数中修改的成员数据,这仅应在成员数据不影响对象的外部可见状态的情况下使用。
class C
{
public:
const C& foo() { return * this; } // should be declared const
const int& getData() { return m_i; } // should be declared const
int bar() const { return m_mi; } // ok to declare const
private:
int m_i;
mutable int m_mi;
};
参考 Effective C++ Item 21;Industrial Strength C++ 7.13;
【解决方案8】:
开头的常量适用于返回值。最后的 const 适用于方法本身。当您将方法声明为“const”时,您表示您无意修改该方法中类的任何成员变量。编译器甚至会做一些基本的检查以确保该方法不会修改成员变量。返回值中的 const 防止调用者修改返回的值。当您返回指向类管理的数据的指针或引用时,这可能很有用。这样做通常是为了避免返回复杂数据的副本,这在运行时可能会很昂贵。
您有两个不同的运算符的原因是“const”版本返回一个指向可能是类内部数据的 const 指针。如果类的实例是 const,那么您可能希望返回的数据也应该是 const。 “非常量”版本只是提供了一个方法,当调用者有一个类的非常量实例时,该方法返回一个可修改的返回值。