c++ const 成员函数和mutable
2012-05-16 14:13 youxin 阅读(1416) 评论(0) 编辑 收藏 举报常量(const)成员函数:承诺不会修改对象的状态
以下程序中,类stack 的成员函数GetCount 仅用于计数,从逻辑上讲GetCount 应当为const 函数。编译器将指出GetCount 函数中的错误。
class Stack { public: void Push(int elem); int Pop(void); int GetCount(void) const; // const 成员函数 private: int m_num; int m_data[100]; }; int Stack::GetCount(void) const { ++ m_num; // 编译错误,企图修改数据成员m_num Pop(); // 编译错误,企图调用非const 函数 return m_num; }
const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大
概是因为其它地方都已经被占用了。有时候要在const 成员函数中调用非const 成员函数,怎么办?
当然有不少办法,个人觉得,最简单的方法可以这样:
写一个全局函数,非const 成员函数的类指针作为参数,然后在这个全局函数中调用想要调用的非const 成员函数。如,
static void get_xxx(Student *s){s->get_xxx();}
什么时候函数写成const常量成员函数?
如果函数会改变一个对象的状态,那它就应该成为这个对象的成员。
class Text { public: const std::size_t length() const; // 返回文本的长度 // 第一个 const 表示 函数返回一个常量,不可作为左值使用 // 第二个 const 表示 函数不修改 Text 类中的数据成员(除了 static 和 mutable 修饰过的) private: char* data; };
mutable的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。
在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
下面是一个小例子:
class ClxTest { public: void Output() const; }; void ClxTest::Output() const { cout << "Output for test!" << endl; } void OutputTest(const ClxTest& lx) { lx.Output(); } |
类ClxTest的成员函数Output是用来输出的,不会修改类的状态,所以被声明为const的。
函数OutputTest也是用来输出的,里面调用了对象lx的Output输出方法,为了防止在函数中调用其他成员函数修改任何成员变量,所以参数也被const修饰。
如果现在,我们要增添一个功能:计算每个对象的输出次数。如果用来计数的变量是普通的变量的话,那么在const成员函数Output里面是不能修改该变量的值的;而该变量跟对象的状态无关,所以应该为了修改该变量而去掉Output的const属性。这个时候,就该我们的mutable出场了——只要用mutalbe来修饰这个变量,所有问题就迎刃而解了。
下面是修改过的代码:
class ClxTest { public: ClxTest(); ~ClxTest(); void Output() const; int GetOutputTimes() const; private: mutable int m_iTimes; }; ClxTest::ClxTest() { m_iTimes = 0; } ClxTest::~ClxTest() {} void ClxTest::Output() const { cout << "Output for test!" << endl; m_iTimes++; } int ClxTest::GetOutputTimes() const { return m_iTimes; } void OutputTest(const ClxTest& lx) { cout << lx.GetOutputTimes() << endl; lx.Output(); cout << lx.GetOutputTimes() << endl; } |
计数器m_iTimes被mutable修饰,那么它就可以突破const的限制,在被const修饰的函数里面也能被修改。
const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间。
static表示的是静态的。类的静态成员函数、静态成员变量是和类相关的,而不是和类的具体对象相关的。即使没有具体对象,也能调用类的静态成员函数和成员变量。一般类的静态函数几乎就是一个全局函数,只不过它的作用域限于包含它的文件中。
在C++中,static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现文件中初始化,如:double Account::Rate=2.25;static关键字只能用于类定义体内部的声明中,定义时不能标示为static
在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数。
const数据成员 只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static const。
#include<iostream> using namespace std; class A{ private: static int a;//只是声明,没有定义 int b; const int c; const static int d=4;//可以直接初始化,或者在类外:const int A::d=0;//注意:给静态成员变量赋值时,不需要加static修饰符。但要加const
public: A():c(3){ b=2; } //{ c =3;}错误,表达式必须是可修改的左值 void output() const{ a++;//ok,b++是错误的,: 由于正在通过常量对象访问“b”,因此无法对其进行修改 cout<<a<<ends<<b<<ends<<c<<ends<<d<<endl; } }; int A::a=1; int main() { A a; a.output(); }
参考了:
http://blog.csdn.net/yjkwf/article/details/6067267