“ const”在 C + + 中有多少种用法?

作为一个 C + + 程序员的新手,有一些结构在我看来仍然非常模糊,其中之一就是 const。你可以在如此多的地方使用它,有如此多不同的效果,对于一个初学者来说几乎不可能活着出来。会不会有一些 C + + 大师永远解释一次各种各样的用法,以及是否和/或为什么不使用它们?

32211 次浏览

试图收集一些用途:

将某个临时值绑定到引用到常量,以延长其生存期。引用可以是一个基函数——它的析构函数不需要是虚函数——正确的析构函数仍然被调用:

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非常数版本将更喜欢非常数版本的 operator[]和 GCC 将创建一个备份内存缓冲区的副本,因为我们可以改变它,它一定不能影响 a的数据!

int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}

对于复制构造函数从 const 对象和临时对象制作副本 :

struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};

为了制造不能改变的常数

double const PI = 3.1415;

通过引用而不是通过值 传递任意对象-以防止可能昂贵或不可能的通过值传递

void PrintIt(Object const& obj) {
// ...
}

在 C + + 中,const 有两个主要用途。

常量值

如果一个值的形式是变量、成员或参数,在其生存期内不会(或不应该)改变,则应该标记它为 const。这有助于防止对象发生突变。例如,在下面的函数中,我不需要更改传递的 Student 实例,因此我将其标记为 const。

void PrintStudent(const Student& student) {
cout << student.GetName();
}

你为什么要这么做。如果您知道基础数据不能更改,那么对算法进行推理就容易得多。“ const”有所帮助,但不能保证这一点能够实现。

显然,将数据打印到 cout 并不需要太多的思考:)

将成员方法标记为 const

在前面的例子中,我将 Student 标记为 const。但是 C + + 怎么知道在 Student 上调用 GetName ()方法不会改变对象呢?答案是该方法被标记为 const。

class Student {
public:
string GetName() const { ... }
};

标记一个方法“ const”有两个作用。主要它告诉 C + + 这个方法不会改变我的对象。第二件事是,现在所有成员变量都将被视为标记为 const。这有助于但不妨碍您修改类的实例。

这是一个非常简单的例子,但是希望它能帮助你回答你的问题。

注意理解这4个声明之间的区别:

以下两个声明在语义上是相同的。你可以改变 哪里 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

作为一个小注意,当我阅读 给你时,注意到这一点是很有用的

const适用于它左边的任何东西(除非 那里没有任何东西,在这种情况下,它适用于它的任何东西 即时权利)。