C++总的const使用说明
1. const修饰类成员变量
程序:
#include <iostream> using namespace std; class A { public: A(int size) : SIZE(size) {}; private: const int SIZE; }; int main() { A a(100); }
说明:
(1) 在类中声明变量为const类型,但是不可以初始化;
(2) const常量类的成员变量的初始化必须在构造函数初始化列表中初始化,而不可以在构造函数函数体内初始化。
(3) 如果其作为C类的成员定义,因为不可以在C类定义创建对象,则可以采用如下措施:
使用指针,然后在C类的构造函数中,用new 在堆空间创建对象,然后天数const的成员初始化。
此时的const变量属于具体的一个对象,如何在整个类中都恒定不变呢?
答案是利用枚举
#include <iostream> using namespace std; class A { private: enum {SIZE = 100}; public: int array[SIZE]; }; int main() { A a; }
问题说明:
(1)枚举常量不会占据对象的存储空间,在编译时被全部求值
(2)但是,它隐含的数据对象类型为整形,不能表示其他类型。
2. 必须在构造函数的初始化列表中初始化的情况
(1)类的const常量;
(2)类的引用类型成员;
#include <iostream> using namespace std; class A { public: A(int &v) : i(v), p(v), j(v) {} void print_val() { cout << "hello:" << i << " " << j << endl;} private: const int i; int p; int &j; }; int main(int argc ,char **argv) { int pp = 45; A b(pp); b.print_val(); }
究其因
① const对象或引用只能初始化但是不能赋值。
② 构造函数的函数体内只能做赋值而不是初始化,因此初始化const对象或引用的唯一机会是构造函数函数体之前的初始化列表中。
③ 明白两个概念:
从无到有叫初始化,初始化(调用拷贝构造函数)创建了新对象;
赋值(调用赋值操作符)没有创建新对象,而是对已有的对象赋值。
(3)没有默认构造函数的类类型成员
#include <iostream> using namespace std; class Base { public: Base(int a) : val(a) {} private: int val; }; class A { public: A(int v) : p(v), b(v) {} void print_val() { cout << "hello:" << p << endl;} private: int p; Base b; }; int main(int argc ,char **argv) { int pp = 45; A b(pp); b.print_val(); }
原因同样是创建对象时,要初始类成员的每一个成员。
(4)如果类存在继承关系,派生类必须在其初始化列表中调用基类的构造函数;
#include <iostream> using namespace std; class Base { public: Base(int a) : val(a) {} private: int val; }; class A : public Base { public: A(int v) : p(v), Base(v) {} void print_val() { cout << "hello:" << p << endl;} private: int p; }; int main(int argc ,char **argv) { int pp = 45; A b(pp); b.print_val(); }
3. const成员函数
(1) 任何不修改数据成员的函数都应该声明为const类型。
如果在编写const成员函数时,①不慎修改了数据成员,②或调用了其他非const成员函数,编译器就会指出错误。应该养成一个好的习惯。
注意:在const修饰类的成员数据时,一般在const声明在函数声明的后边;
#include <iostream> using namespace std; class Stack { public: void Push(int item); int Pop(void); int GetCount(void) const;//const 后置 private: int m_num; int m_data[100]; }; int Stack::GetCount(void) const { ++m_num; //编译错误,企图修改数据成员 Pop(); //编译错误,企图调用非const函数 return m_num; }
(2)同一个类中,可以仅通过是否是const定义两个函数名字、参数、返回值完全相同的两个成员函数,依据类对象是否为const对象分别调用。
程序:
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void print_val() const { cout << "const print_val:" << val << endl;} private: int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A a(12); a.print_val(); }
输出:
总结:
同函数名、参数、返回值可以仅通过是否为const来定义为类的两个成员函数。
在调用时,const对象调用const成员函数,非const对象调用非const成员函数。
4. const的一些问题
(1)不可以在const函数中改变成员变量的值,那么有没有办法改变?
答案是可以的,把成员变量声明为mutable类型。看程序
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void print_val() const { val++; cout << "const print_val:" << val << endl;} private: mutable int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); const A a(12); a.print_val(); }
输出:
说明:
mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。
在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰
(2)当类中只有const函数,非const对象是否可以调用const函数?
答案是可以的,范围并没有被扩大。
但是:只有const函数时,非const对象不可以调研那个const函数(否则,类的数据变量就会发生变化)。
(3)当类中存在只有 是否为const 不同的两个函数时,const函数是否可以暂时调用那个非const函数?
答案是可以的。用const_cast将转化掉表达式的const性质
#include <iostream> using namespace std; class A { public: A(int v): val(v) {} void print_val() { cout << "not const:" << val << endl;} void const print_val() const { cout << "const print_val:" << val << endl;} private: int val; }; int main(int argc ,char **argv) { A b(45); b.print_val(); //非const const A *a = new A(45); const_cast<A*>(a)->print_val(); //()调用非const的重载函数 a->print_val(); //调用const的从在函数 }
输出:
注意;const_cast<A*> (a)只对本地转化有效,且必须使用类的指针进行处理。
单纯用类转化不行,直接用类的对象不行。
const A a(45); const_cast<A> a.print_val();
编译不通过,错误
(4)返回类型是const是怎么回事?
const返回类型只有在修饰指针或引用是才有用。单凭const返回类型不可以重载。
参考网址:
http://www.cnblogs.com/kaituorensheng/p/3244910.html