const修饰成员函数及其相关

来源:互联网 发布:pi数据库软件 编辑:程序博客网 时间:2024/05/10 02:50

为了更清晰明了的引出本篇博客所要探讨的问题,还是以一段代码作为开端(一个简单的日期类)

class Date{public:Date(int year=1900, int month=1, int day=1):_year(year), _month(month), _day(day){cout << "Date()" << endl;}Date(const Date&d){cout << "Date(const Date&d)" << endl;}void Display(){cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl;}private:int _year;//年int _month;//月int _day;//日};void f(const Date&d){d.Display();}void test(){Date d1;f(d1);}int main(){test();system("pause");return 0;}
在test()函数中,我们目的是:想用已经构建好的的的d1对象作为f()函数的参数传入,并打印日期。

然而这个程序编译都是不通过的

这里我们用一幅图来具体展现一下此处的函数传参是怎样一步步进行的--->


此处又牵扯到了当初学习c语言时的一个最易混淆的问题:const关键字修饰变量;这里我们再回顾一下(就以上面红色字体代码为例):

(1)对于指针变量p1,const放在了类型int之前,修饰的是p1所指向的内容,也就是说p1所指向的内容是受const保护的,用户不能通过“解引用”来改变a的值;即

int a = 10;const int*p1 = &a;*p1 = 3;

是错误的,编译不通过。

(2)对于指针变量p2,const虽然放在了类型int之后,但是在“ *”之前,它所修饰的与p1相同,依旧是其指向的内容,不能通过“解引用”来改变。

(3)对于指针变量p3,const放在了int*之后,修饰的是变量本身而不是p3所指向的内容,即我们可以通过“解引用”来改变a的值,但是不能改变p3所指向的地址;即:

int a = 10;int*const p3 = &a;*p3 = 20;
这是完全正确的

int a = 10;int b = 20;int*const p3 = &a;p3 = &b;
int a = 10;const int*p1 = &a;int*p5 = p1;


这就错了,编译不通过

(4)对于指针变量p4,这里的意思是p4不能够改变,且p4指向的内容也不能被改变,(即以下代码是错误的)

int a = 10;int b = 20;const int*const p4 = &a;*p4 = 20;p4 = &b;

--------------------------------------------------------------------------------------------------------------------------------------------------------------

下来我们再来看这样一段代码:

int a = 10;const int*p1 = &a;int*p5 = p1;
思考:这里可以赋值成功吗?

答案是:不行;为什么呢?由上面例题的讲解我们不能得知,此处const修饰的是p1所指向的内容,不能被改变。而接下来int*p5=p1;这句代码把p1变量赋值给p5,是想通过P5改变p1的内容,显然是不可以的;再者,“ =”两边类型都不一致。所以编译不通过


再来看下面一段代码:思考编译会通过吗?

int a = 10;int*const p3 = &a;int*p6 = p3;
答案是:正确。const修饰的是p3变量本身,是不能被改变的;相当于是把一个常量值赋值给p6,所以是合理的。

综上,我们再次回到本文最开始那段代码要讨论的问题上,实质就是:


const修饰的指针变量赋值给非const所修饰的指针变量(这里参考上面紫色字体所讲部分)显然是不正确的,要想编译通过,必须this指针也用const修饰,即const Date*this。那么要想达到这种效果,则const必须放在函数名字之后,即如下:

//void Display(const Date*this)void Display()const{cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl;}

这样达到的效果才是:const Date*this.也就引出了本文一开始讨论的要点:const修饰成员函数,它修饰的是this指针所指向的内容,不能被改变(即就是上边Display()函数体中加上this->_year = 12;是编译不通过的)

所以如果不希望成员变量被随意改变,那么就可以用const来修饰成员函数,这样一来const对象和非const对象都可以调用成员函数。

1 .   cons t 对象可以调用非cons t 成员函数和cons t 成员函数吗?

答:不可以(1)

答:可以(2)
2 .   非cons t 对象可以调用非cons t 成员函数和cons t 成员函数吗?

答:可以(1)

答:可以(2)
3 .   cons t 成员函数内可以调用其它的cons t 成员函数和非cons t 成员函数吗?

答:可以(1)

答:不可以(2)

例(2)

//void Display(const Date*this)//d1.Display();void Display()const//const成员函数{cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl;f();//this->f(this)}void f()//非const成员函数 Date*this{}
对象调用成员函数时,成员函数再包含成员函数时,它的调用过程是这样的:把对象的地址传递给this指针,再通过this指针传递过去,调用f()函数,即调用f();就相当于this->f(this);而this指针是被const修饰的(从Display函数中得出,即const Date*this),那么它就不可以传给f()函数,因为f()的参数类型时Date*this.


4 .   非cons t 成员函数内可以调用其它的cons t 成员函数和非cons t 成员函数吗?

答:可以(1)

答:可以(2)

例(1)

//void Display(const Date*this)void Display()const//const成员函数{cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl;}void f()//非const成员函数{//this->Display(this);Display();}

-------------------------------------------------------------------------------------------------------------------------------------------------

最后再来说明一个问题取地址运算符&的重载。还是以上面的代码为例,只不过加上了printf("%p\n",&d1);

int main(){ Date d1;printf("%p\n", &d1);return 0;}
运行结果:

这里我们并没有写&的重载,但是系统会自动调用,怎么来说明这个问题呢?可以这样,在类的公用接口中手动写&的重载,并打印出来;这样只要一调用就会输出函数体中的语句

public:Date* operator &(){cout << "Date* operator &()" << endl;return this;}int main(){const Date d1;printf("%p\n", &d1);return 0;}

运行结果:


可以看出,完全证实了我们的猜想:如果没有写&的重载,则会自动调用系统生成的。

但是:如果对象是被const修饰的,那么还用调用系统自动生成的吗?(请看下面的代码)

public:Date* operator &(){cout << "Date* operator &()" << endl;return this;}int main(){const Date d1;printf("%p\n", &d1);//d1.operator(&d1)return 0;}

运行结果:


可见并没有调用,实际上根本就调用不到,为什么呢?这里&d1,调用运算符的重载,是被const修饰的;但是在Date* operator&()这里传给了一个非const修饰的this指针,由前边我们所讲,这是不对的。这时候就需要给一个重载函数:

const Date* operator &()const{cout << "Date* operator &()const" << endl;return this;}






0 0