{"id":"58954456","type":"page","status":"current","title":"04.C++面向对象模型初探","version":{"by":{"type":"known","username":"ethanliu","userKey":"2c90931b6cfb654f016d5c69becc0001","profilePicture":{"path":"/images/icons/profilepics/default.svg","width":48,"height":48,"isDefault":true},"displayName":"刘浩","_links":{"self":"https://wiki.suncaper.net/rest/api/user?key=2c90931b6cfb654f016d5c69becc0001"},"_expandable":{"status":""}},"when":"2022-07-09T01:51:24.000Z","message":"","number":1,"minorEdit":false,"hidden":false,"_links":{"self":"https://wiki.suncaper.net/rest/experimental/content/58954456/version/1"},"_expandable":{"content":"/rest/api/content/58954456"}},"body":{"storage":{"value":"

4.4 C++面向对象模型初探

4.4.1 成员变量和函数的存储

c语言中,“分开来声明的,也就是说,语言本身并没有支持“数据”和“函数”之间的关联性我们把这种程序方法称为“程序性的”,由一组“分布在各个以功能为导航的函数中”的算法驱动,它们处理的是共同的外部数据。

 

c++实现了“封装”,那么数据(成员属性)和操作(成员函数)是什么样的呢?

“数据”和“处理数据的操作(函数)”是分开存储的。

  • c++中的非静态数据成员直接内含在类对象中,就像c struct一样。
  • 成员函数(member function)虽然内含在class声明之内,却不出现在对象中。
  • 每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.


cpp

4.4.2 this指针

4.4.2.1 this指针工作原理

通过上例我们知道,c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

那么问题是:这一块代码是如何区分那个对象调用自己的呢?

c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象。

       c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。

   this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认设置。

this指针永远指向当前对象

成员函数通过this指针即可知道操作的是那个对象的数据。This指针是一种隐含指针,它隐含于每个类的非静态成员函数中。This指针无需定义,直接使用即可。

注意:静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。

4.4.2.2 this指针的使用

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this.


cppname = name;\n\t\tthis->age = age;\n\t}\n\t//2. 返回对象本身的引用\n\t//重载赋值操作符\n\t//其实也是两个参数,其中隐藏了一个this指针\n\tPerson PersonPlusPerson(Person& person){\n\t\tstring newname = this->name + person.name;\n\t\tint newage = this->age + person.age;\n\t\tPerson newperson(newname, newage);\n\t\treturn newperson;\n\t}\n\tvoid ShowPerson(){\n\t\tcout << \"Name:\" << name << \" Age:\" << age << endl;\n\t}\npublic:\n\tstring name;\n\tint age;\n};\n\n//3. 成员函数和全局函数(Perosn对象相加)\nPerson PersonPlusPerson(Person& p1,Person& p2){\n\tstring newname = p1.name + p2.name;\n\tint newage = p1.age + p2.age;\n\tPerson newperson(newname,newage);\n\treturn newperson;\n}\n\nint main(){\n\n\tPerson person(\"John\",100);\n\tperson.ShowPerson();\n\n\tcout << \"---------\" << endl;\n\tPerson person1(\"John\",20);\n\tPerson person2(\"001\", 10);\n\t//1.全局函数实现两个对象相加\n\tPerson person3 = PersonPlusPerson(person1, person2);\n\tperson1.ShowPerson();\n\tperson2.ShowPerson();\n\tperson3.ShowPerson();\n\t//2. 成员函数实现两个对象相加\n\tPerson person4 = person1.PersonPlusPerson(person2);\n\tperson4.ShowPerson();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]>

4.4.2.3 const修饰成员函数

  • const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量
  • 当成员变量类型符前用mutable修饰时例外。
cppmAge = 0;\n\t\tthis->mID = 0;\n\t}\n\t//在函数括号后面加上const,修饰成员变量不可修改,除了mutable变量\n\tvoid sonmeOperate() const{\n\t\t//this->mAge = 200; //mAge不可修改\n\t\tthis->mID = 10;\n\t}\n\tvoid ShowPerson(){\n\t\tcout << \"ID:\" << mID << \" mAge:\" << mAge << endl;\n\t}\nprivate:\n\tint mAge;\n\tmutable int mID;\n};\n\nint main(){\n\n\tPerson person;\n\tperson.sonmeOperate();\n\tperson.ShowPerson();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]>

4.4.2.4 const修饰对象(常对象)

  • 常对象只能调用const的成员函数
  • 常对象可访问 const 或非 const 数据成员,不能修改,除非成员用mutable修饰
cppmAge = 0;\n\t\tthis->mID = 0;\n\t}\n\tvoid ChangePerson() const{\n\t\tmAge = 100;\n\t\tmID = 100;\n\t}\n\tvoid ShowPerson(){\n this->mAge = 1000;\n\t\tcout << \"ID:\" << this->mID << \" Age:\" << this->mAge << endl;\n\t}\n\npublic:\n\tint mAge;\n\tmutable int mID;\n};\n\nvoid test(){\t\n\tconst Person person;\n\t//1. 可访问数据成员\n\tcout << \"Age:\" << person.mAge << endl;\n\t//person.mAge = 300; //不可修改\n\tperson.mID = 1001; //但是可以修改mutable修饰的成员变量\n\t//2. 只能访问const修饰的函数\n\t//person.ShowPerson();\n\tperson.ChangePerson();\n}]]>


","representation":"storage","_expandable":{"content":"/rest/api/content/58954456"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954456","edit":"/pages/resumedraft.action?draftId=58954456","tinyui":"/x/2JKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954456"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954456/child","restrictions":"/rest/api/content/58954456/restriction/byOperation","history":"/rest/api/content/58954456/history","ancestors":"","descendants":"/rest/api/content/58954456/descendant","space":"/rest/api/space/2CT"}}