详解C++中的this指针与常对象
C++ this指针详解 Student stu; //通过Student类来创建对象 Student *pStu = &stu; [示例] 通过 this 来访问成员变量: class Student{ private: char *name; int age; float score; public: void setname(char *); void setage(int); void setscore(float); }; void Student::setname(char *name){ this->name = name; } void Student::setage(int age){ this->age = age; } void Student::setscore(float score){ this->score = score; } 本例中,函数参数和成员变量重名是没有问题的,因为通过 this 访问的是成员变量,而没有 this 的变量是函数内部的局部变量。例如对于this->name = name;语句,赋值号左边是类的成员变量,右边是 setname 函数的局部变量,也就是参数。 下面是一个完整的例子: #include <iostream> using namespace std; class Student{ private: char *name; int age; float score; public: void setname(char *); void setage(int); void setscore(float); void say(); }; void Student::setname(char *name){ this->name = name; } void Student::setage(int age){ this->age = age; } void Student::setscore(float score){ this->score = score; } void Student::say(){ cout<<this->name<<"的年龄是 "<<this->age<<",成绩是 "<<this->score<<endl; } int main(){ Student stu1; stu1.setname("小明"); stu1.setage(15); stu1.setscore(90.5f); stu1.say(); Student stu2; stu2.setname("李磊"); stu2.setage(16); stu2.setscore(80); stu2.say(); return 0; } 运行结果: 小明的年龄是 15,成绩是 90.5 李磊的年龄是 16,成绩是 80 对象和普通变量类似;每个对象都占用若干字节的内存,用来保存成员变量的值,不同对象占用的内存互不重叠,所以操作对象A不会影响对象B。 上例中,创建对象 stu1 时,this 指针就指向了 stu1 所在内存的首字节,它的值和 &stu1 是相同的;创建对象 stu2 时,this 等于 &stu2;创建对象 stu3 时也一样。 我们不妨来证明一下,给 Student 类添加一个成员函数,输出 this 的值,如下所示: void Student::printThis(){ cout<<this<<endl; }
Student stu1,*pStu1 = &stu1; stu1.printThis(); cout<<pStu1<<endl; Student stu2,*pStu2 = &stu2; stu2.printThis(); cout<<pStu2<<endl; 运行结果: 0x28ff30 0x28ff30 0x28ff10 0x28ff10 可以发现,this 确实指向了当前对象的首地址,而且对于不同的对象,this 的值也不一样。 几点注意: 实际上,this 指针是作为函数的参数隐式传递的,它并不出现在参数列表中,调用成员函数时,系统自动获取当前对象的地址,赋值给 this,完成参数的传递,无需用户干预。 this 作为隐式参数,本质上是成员函数的局部变量,不占用对象的内存,只有在发生成员函数调用时才会给 this 赋值,函数调用结束后,this 被销毁。 正因为 this 是参数,表示对象首地址,所以只能在函数内部使用,并且对象被实例化以后才有意义。 C++常对象及其成员 既要使数据能在一定范围内共享,又要保证它不被任意修改,这时可以使用const,即把有关的数据定义为常量。 在定义对象时指定对象为常对象。常对象必须要有初值,如: Time const t1(12,34,46); //t1是常对象
定义常对象的一般形式为: 类名 const 对象名[(实参表列)];
const 类名 对象名[(实参表列)]; 二者等价。 如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由系统自动调用的隐式的构造函数和析构函数)。例如,对于例9.7中已定义的Time类,如果有 const Time t1(10,15,36); //定义常对象t1 t1.get_time( ); //企图调用常对象t1中的非const型成员函数,非法
不能仅依靠编程者的细心来保证程序不出错,编译系统充分考虑到可能出现的情况,对不安全的因素予以拦截。现在,编译系统只检查函数的声明,只要发现调用了常对象的成员函数,而且该函数未被声明为const,就报错,提请编程者注意。 引用常对象中的数据成员很简单,只需将该成员函数声明为const即可。如: void get_time( ) const ; //将函数声明为const
常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。有时在编程时有要求,一定要修改常对象中的某个数据成员的值,ANSI C++考虑到实际编程时的需要,对此作了特殊的处理,对该数据成员声明为mutable,如: mutable int count;
可以将对象的成员声明为const,包括常数据成员和常成员函数。 1) 常数据成员 有一点要注意: 只能通过构造函数的参数初始化表对常数据成员进行初始化。如在类体中定义了常数据成员hour: const int hour; //声明hour为常数据成员 不能采用在构造函数中对常数据成员赋初值的方法,下面的做法是非法的: Time::Time(int h){ hour=h; } // 非法
在类外定义构造函数,应写成以下形式: Time::Time(int h):hour(h){} //通过参数初始化表对常数据成员hour初始化
void get_time( ) const ; //注意const的位置在函数名和括号之后
那么怎样利用常成员函数呢? 如果在一个类中,有些数据成员的值允许改变,另一些数据成员的值不允许改变,则可以将一部分数据成员声明为const,以保证其值不被改变,可以用非const的成员函数引用这些数据成员的值,并修改非const数据成员的值。 如果要求所有的数据成员的值都不允许改变,则可以将所有的数据成员声明为const,或将对象声明为const(常对象),然后用const成员函数引用数据成员,这样起到“双保险”的作用,切实保证 如果已定义了一个常对象,只能调用其中的const成员函数,而不能调用非const成员函数(不论这些函数是否会修改对象中的数据)。这是为了保证数据的安全。如果需要访问对象中的数据成员,可将常对象中所有成员函数都声明为const成员函数,但应确保在函数中不修改对象中的数据成员。 不要误认为常对象中的成员函数都是常成员函数。常对象只保证其数据成员是常数据成员,其值不被修改。如果在常对象中的成员函数未加const声明,编译系统把它作为非const成员函数处理。 还有一点要指出,常成员函数不能调用另一个非const成员函数。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |