C++核心编程 4 类和对象 - C++对象模型和this指针(3)
4.3.1成员变量和成员函数分开存储
在C++中,类内的成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上
/*class person { }; void test1() { person p; //空对象占用内存空间为: 0 ? 4 ? 1 ? cout << "size of p = " << sizeof(p) << endl; //size of p = 1 //C++编译器会给每个空对象也分配一个字节的空间,是为了区分空对象占内存的位置 //每个空对象也应该有个独一无二的内存地址 }*/ //成员函数和成员变量是分开存储的 class person { int m_a; //非静态成员变量 属于类的对象上 static int m_b; //静态成员变量 不属于类对象上 void func() {} //非静态成员函数 不属于类对象上 static void func2() {} //静态成员函数 不属于类对象上 }; int person::m_b = 0; void test1() { person p; //此时类内有对象占用的内存空间为: 0? 4? 1? cout << "size of p = " << sizeof(p) << endl; //size of p = 4 } int main() { test1(); system("pause"); return 0; }
4.3.2 this指针概念
通过4.3.1了解到在C++中成员变量和成员函数是分开存储的,每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会公用同一块代码,那么问题是:这一块代码是如何区分哪个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
1、当形参和成员变量同名时,可用this指针来区分;
2、在类的非静态成员函数中返回对象本身,可使用 return *this
class Person { public: Person(int age) { //m_age = age; //要么形参与成员变量不同名 要么用this //this指针指向的是被调用的成员函数所属的对象 this->age = age; } //int m_age; int age; //void PersonAddAge(Person p) Person& PersonAddAge(Person p) //因为return了*this 所以不能用void,而是以引用的方式返回,返回的是这个对象的本身,如果不带引用,执行完一次p2.PersonAddAge(p1)函数后,再执行一次会将之前的覆盖掉,返回的就不是这个对象本身,而是拷贝出来的副本 { this->age += p.age; return *this; //返回类型为*this等同于返回值类型为p2 this指向p2的指针,而*this指向的就是p2这个对象的本体 刚才没加爽,现在让你加爽 } }; //1、解决名称冲突 void test1() { Person p1(18); //cout << "p1 age = " << p1.m_age << endl; cout << "p1 age = " << p1.age << endl; } //2、返回对象本身用 *this void test2() { Person p1(10); Person p2(10); //p2.PersonAddAge(p1); //p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1) 没加爽,想再加几次p1的年龄 这样不行 因为 p2.PersonAddAge(p1)返回值类型为p2,而PersonAddAge(Person p)函数的返回值类型为void。类型不同,不能连续调用(链式调用 //链式编程思想 p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1); //刚才没加爽,现在让你加爽 cout << "p2 age = " << p2.age << endl; } int main() { //test1(); test2(); system("pause"); return 0; }
4.3.3空指针访问成员函数
c++中空指针也是可以调用成员函数的,但是要注意到有没有用到this指针,如果用到了this指针,需要加以判断保证代码的健壮性
class Person { public: void showClassName() { cout << "this is person class" << endl; } void showPersonAge() { //报错原因是因为传入的指针为 NULL if (this == NULL) { return; } cout << "age = " << m_Age << endl; //实际上是 cout << "age = " << this->m_Age << endl; 因为Person* p = NULL,这里的this也就默认成了空指针,这里的空指针this是访问不了函数里的成员m_Age的 } int m_Age; }; void test1() { Person* p = NULL; p->showClassName(); p->showPersonAge(); } int main() { test1(); system("pause"); return 0; }
4.3.4 const修饰成员函数
常函数
1、成员函数后加const后,称这个函数是常函数
2、常函数内不可以修改成员属性
3、成员属性声明时加关键字mutable后,在常函数中方可进行修改
常对象
1、声明对象前加const称该对象为常对象
2、常对象只能调用常函数
//常函数 class Person { public: void showPerson() const //不加const的话,在函数体内部可以修改m_A;加上后 等同于Person * const this //在成员函数后面加上const,修饰的是this指针,让指针指向的值也不可以修改 //this指针的本质是指针常量 指针的指向是不可以修改的 { this->m_B = 100; //this->m_A = 100; //m_A = 100; this = NULL; //this指针是不可以修改指针的指向的 } void func() { m_A = 100; } int m_A; mutable int m_B; //特殊变量,即使在常函数中,也可以修改这个值 }; void test1() { Person p; p.showPerson(); } //常对象 void test2() { const Person p; //在对象前加const,变为常对象 p.m_A = 100; p.m_B = 100; //m_B是特殊变量,在常对象下也可以修改这个值 //常对象只能调用常函数 p.showPerson(); p.func(); //常对象只能调用常函数 } int main() { system("paluse"); return 0; }