一、C++中函数和对象
1.const数据成员:跟const常量一样,只是一个在类里(而且是在构造函数里),一个在类外而已,都必须初始化。
2.const成员函数:即普通成员函数后再加const。它可以读取数据成员的值,但不能修改它们。若要修改时,数据成员前必须加mutable。以指定其可被任意更改。mutable是ansi c++考虑到实际编程时,可能一定要修改const对象中的某个数据成员而设的。const成员函数可以被相同参数表的非const成员函数重载。
3.普通对象:可以调用任意成员函数。见下面的例子
4.const对象:仅能调用const成员函数,但是构造函数和析构函数是唯一不是const成员函数却可以被const对象调用的成员函数。
二、例1
class Point { public: int GetX() const; int GetY() const; void SetPt (int, int); void OffsetPt (int, int); private: int xVal, yVal; }; int Point::GetY() const//const 成员函数应该在函数原型说明和函数定义中都增加const 限定: { return yVal; }
三、例2
class Set { public: Set (void){ card = 0; } bool Member(const int) const; void AddElem(const int); //... private: int card; }; bool Set::Member (const int elem) const { //... }非常量成员函数不能被常量成员对象调用,因为它可能企图修改常量的数据成员:
const Set s;
s.AddElem(10); // 非法: AddElem 不是常量成员函数
s.Member(10); // 正确
但构造函数和析构函数对这个规则例外,它们从不定义为常量成员,但可被常量对象调用(被自动调用)。它们也能给常量的数据成员赋值。
四、最后一个例子
class A{ public: const int a; int b; A(int n1,int n2):a(n1),b(n2){} void printA(){//非const成员函数printA cout<<a<<endl; } void printB()const{//const成员函数printB cout<<b<<endl; } }; int main() { const A a1(2,3);//定义一个const成员,它可以使用构造函数初始化const成员a和非const成员b A a2(4,5);//定义一个非const成员,可以使用构造函数初始化const成员a和非const成员b a1.printA();//编译不通过,非const成员函数被const对象使用 a2.printA();//编译通过,非const成员函数只是指定调用它的对象得是const //-----作为const成员函数printB,保证自己不修改成员a1,但不对a1做指定,a1可以是const也可以是非const a1.printB(); a2.printB(); }
五、More to Tell
1.将const放在函数参数表和函数体之间是指定const成员函数,对于普通函数不可如此指定,也没有任何意义。
2.关键字const必须同样的出现在函数实现里,否则编译器会将这个函数实现当作另外一个重载版本(非const成员函数)
3.非const成员函数可以调用const成员函数,但是const成员函数不允许掉用非const成员函数,因为它可能会修改const对象成员的值。
4.对于类内有const函数与非const函数重载的情况,非const成员调用该函数编译器默认调用非const版本,那么如何调用const版本的函数呢?其实只需要转型就可以了。
class A{ public: const int a; int b; A(int n1,int n2):a(n1),b(n2){} void printA(){//非const成员函数printA cout<<a<<endl; } void printA()const{//const成员函数printB cout<<b<<endl; } }; int main() { A a2(1,10);//定义一个非const成员,可以使用构造函数初始化const成员a和非const成员b a2.printA();//默认调用非const版本,结果为1 static_cast<const A>(a2).printA();//强制转型为const对象,调用const版本,结果为10 }