作为一名新手C ++程序员,有些构造看起来仍然非常模糊,其中一个是const
。你可以在很多地方使用它,并且有很多不同的效果,初学者几乎不可能活着出来。一些C ++专家会永远解释各种用途以及是否和/或为什么不使用它们?
答案 0 :(得分:98)
尝试收集一些用途:
将一些临时绑定到引用到const,以延长其生命周期。引用可以是基础 - 并且它的析构函数不需要是虚拟的 - 正确的析构函数仍然是称为:
ScopeGuard const& guard = MakeGuard(&cleanUpFunction);
解释,使用代码:
struct ScopeGuard {
~ScopeGuard() { } // not virtual
};
template<typename T> struct Derived : ScopeGuard {
T t;
Derived(T t):t(t) { }
~Derived() {
t(); // call function
}
};
template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); }
这个技巧在Alexandrescu的ScopeGuard实用程序类中使用。一旦临时超出范围,Derived的析构函数就会被正确调用。上面的代码错过了一些小细节,但这对它来说很重要。
使用const告诉其他人方法不会改变此对象的逻辑状态。
struct SmartPtr {
int getCopies() const { return mCopiesMade; }
};
使用const作为写时复制类,使编译器帮助您决定何时何时不需要复制。
struct MyString {
char * getData() { /* copy: caller might write */ return mData; }
char const* getData() const { return mData; }
};
解释:只要原始对象和复制对象的数据保持不变,您可能希望在复制时共享数据。一旦其中一个对象更改了数据,您现在需要两个版本:一个用于原始版本,另一个用于复制。也就是说,您将 复制到任一对象,这样他们现在都拥有自己的版本。
使用代码:
int main() {
string const a = "1234";
string const b = a;
// outputs the same address for COW strings
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
上面的代码片段在我的GCC上打印相同的地址,因为使用的C ++库实现了写时复制std::string
。两个字符串即使是不同的对象,也会为其字符串数据共享相同的内存。使b
非const更喜欢operator[]
的非const版本,而GCC将创建后备内存缓冲区的副本,因为我们可以更改它并且它不得影响{{{{1}的数据1}}!
a
让复制构造函数从const对象和临时对象中复制:
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
制作一些无法改变的常数
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
用于通过引用而不是按值传递任意对象 - 以防止可能昂贵或不可能的按值传递
double const PI = 3.1415;
答案 1 :(得分:26)
在C ++中,const有两个主要用途。
Const值
如果某个值是变量,成员或参数的形式,在其生命周期内不会(或不应该)被更改,则应将其标记为const。这有助于防止对象发生突变。例如,在以下函数中,我不需要更改传递的Student实例,因此我将其标记为const。
void PrintStudent(const Student& student) {
cout << student.GetName();
}
至于你为什么要这样做。如果您知道基础数据不能改变,那么推理算法要容易得多。 “const”有所帮助,但不保证会实现。
显然,将数据打印到cout并不需要太多考虑:)
将成员方法标记为常量
在前面的例子中,我将Student标记为const。但是C ++如何知道在学生上调用GetName()方法不会改变对象?答案是该方法被标记为const。
class Student {
public:
string GetName() const { ... }
};
标记方法“const”可以做两件事。它主要告诉C ++这个方法不会改变我的对象。第二件事是现在所有成员变量都被视为标记为const。这有助于但不会阻止您修改类的实例。
这是一个非常简单的例子,但希望它能帮助回答你的问题。
答案 2 :(得分:15)
注意理解这4个声明之间的区别:
以下2个声明在语义上是相同的。您可以更改其中 ccp1和ccp2指向,但您无法更改他们指向的内容。
const char* ccp1;
char const* ccp2;
接下来,指针是const,所以为了有意义,它必须初始化为指向某个东西。你无法指出其他东西,但它指向的东西可以被改变。
char* const cpc = &something_possibly_not_const;
最后,我们将两者结合起来 - 所以指向的东西无法修改,指针也不能指向其他地方。
const char* const ccpc = &const_obj;
顺时针螺旋规则可以帮助解开声明http://c-faq.com/decl/spiral.anderson.html
答案 3 :(得分:2)
稍微提一下,在我阅读here时,注意到
是很有用的
const
适用于其左边的任何内容(除了if之外) 没有任何东西在哪种情况下它适用于它的任何东西 直接右)。