C++开发初级


877 浏览 5 years, 3 months

6.2 const方法

版权声明: 转载请注明出处 http://www.codingsoho.com/

const方法

常量对象是值不能改变的对象。如果使用常量对象、常量对象的引用以及指向常量对象的指针,编译器将不允许调用对象的任何方法,除非这些方法承诺不改变任何数据成员。为了保证方法不改变数据成员,可以用const关键字标记方法本身。下面的SpreadsheetCell类包含了用const标记的不改变任何数据成员的方法:

class SpreadsheetCell
{
 public:
  double getValue() const;
  string getString() const;
};

代码取自 SpreadsheetCellMethods\SpreadsheetCell.h

Const规范是方法原型的一部分,方法的定义必须与其匹配:

double SpreadsheetCell::getValue() const
{
}
string SpreadsheetCell::getString() const
{
    return mString;
}

代码取自 SpreadsheetCellMethods\SpreadsheetCell.h

将方法标记为const,就是与客户代码立下了契约,承诺不会在方法内改变对象内部的值。如果将实际上修改了数据成员的方法声明为const,编译器将会报错。不能将静态方法声明为const,因为这是多余的。 静态方法没有类的实例,因此不可能改变内部的值。 const的工作原理是将方法内用到的数据成员都标记为const引用,因此如果试图修改数据成员,编译器会报错。

非const对象可以调用const方法以及非const方法。然而,const对象只能调用const方法,下面是一些示例:

  SpreadsheetCell myCell(5);
  cout << myCell.getValue() << endl; // OK
  myCell.set("6"); // OK
  const SpreadsheetCell& anotherCell = myCell;
  cout << anotherCell.getValue() << endl; // OK
  anotherCell.set("6"); // Compilation Error!

代码取自 SpreadsheetCellMethods\SpreadsheetTest.cpp

应该养成习惯,将不修改对象的所有方法声明为const,这样就可以在程序中引用const对象。注意const对象也会被销毁,它们的析构函数也会被调用,因此不应该将析构函数标记为const。

mutable数据成员

有时您编写的方法“逻辑上”是const,但是碰巧改变了对象的数据成员。这个改动对于用户可见的数据没有任何影响,但是在技术上确实做出了改动,因此编译器不会让您将这个方法声明为const。例如,假定您想要让电子表格应用程序获取数据被读取的频率。

完成这个任务的笨办法是在SpreadsheetCell类中加入一个计数器,计算getValue()以及getString()调用的次数。遗憾的是,这样做使得编译器认为这些方法是非const的,这并非您的本意。解决方法是将计数器变量设置为mutable,从而告诉编译器在const()方法中允许改变这个值。下面是新的SpreadsheetCell类定义:

class SpreadsheetCell
{
 protected:
  double mValue;
  string mString;

  mutable int mNumAccesses = 0;
  //mutable int mNumAccesses;   // Pre-C++11
};

代码取自 SpreadsheetCellMethods\SpreadsheetCell.h

下面是getValue()以及getString()的定义:

double SpreadsheetCell::getValue() const
{
    mNumAccesses++;
    return mValue;
}
string SpreadsheetCell::getString() const
{
    mNumAccesses++;
    return mString;
}

代码取自 SpreadsheetCellMethods\SpreadsheetCell.h