一、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
}