第三章 类、class、struct、对象、this
类
- C++中可以使用struct、class来定义一个类
- struct和class的区别
- struct的默认成员权限是public
- class的默认成员权限是private
//用Struct 定义一个类 struct Person { //public: //默认就是public //成员变量、成员方法、函数 int age; // 成员方法 void run() { cout << "run(),ageis:" << age << endl; } }; //class定义一个类 class Student { //private ://默认就是private,一旦私有只能在内部访问 //指定为public public: int no; void study() { cout << "study(): no is " << no << endl; } }; int main() { //创建一个对象,这里不需要new //这个对象分配的内存在栈空间(确切来说就是在main函数的栈空间),不需要手动管理 Person person; person.age = 20; person.run(); Person *rperson = &person; rperson->age = 30; rperson->run(); //在栈中分配一个对象 Student student; student.no = 300; student.study(); getchar(); return 0; }
- 上面代码中person对象、rperson指针、student的内存都是在函数的栈空间,自动分配和回收的
- 可以尝试反汇编struct和class,看看是否有其他区别
- 没有其他区别,仅仅是一个public跟private的区别。
- 实际开发中,用class表示类比较多
C++编程规范
- 每个人都可以有自己的编程规范,没有统一的标准,没有标准答案,没有最好的编程规范
- 变量名规范参考
- 全局变量:g_
- 成员变量:m_
- 静态变量:s_
- 常量:c_
- 使用驼峰标识
对象的内存布局
- 对象占用的内存大小
- 函数是不占用对象的内存的,函数就是代码,函数是每个Person对象公用的,而且就一份
- 因此函数是放在对象外部的
- 即对象的内存只包含他的成员变量
- 函数的调用反汇编就是:
call 函数的地址
- 仅仅就是跳转到函数的地址
struct Person { int m_age; void run() { cout << "run(),m_age is:" << m_age << endl; } }; Person person; person.m_age = 20; person.run(); //打印person对象占用4个字节 //函数是不占用对象的内存的,函数就是代码,函数是每个Person对象公用的,而且就一份 //因此函数是放在对象外部的 //即对象的内存只包含他的成员变量 cout << sizeof(person) << endl;
- 思考:如果类中有多个成员变量,对象的内存又是如何布局的?
-
代码举例:
struct Person { int m_id; int m_age; int m_height; void run() { cout << "run(),m_age is:" << m_age << endl; } }; //调用 //这一句仅仅是分配12个内存 Person person; //将123分配给前4个内存,下面依次 person.m_id = 123; person.m_age = 20; person.m_height = 170; person.run(); cout << "&person==" << &person << endl; cout << "&person.m_id==" << &person.m_id << endl; cout << "&person.m_age==" << &person.m_age << endl; cout << "&person.m_height==" << &person.m_height << endl; cout << sizeof(person) << endl; //打印结果 & person == 0021FD58 &person.m_id == 0021FD58 &person.m_age == 0021FD5C &person.m_height == 0021FD60
-
对象的内存分配图如下:
- 对象的首地址= 对象第一个成员变量的首地址
- 创建对象的本质就是分配内存
- 对象成员变量赋值就是拿到相应的内存赋值
-
- 思考题(仔细看)
-
最后打印出来的每个成员变量值是多少?
struct Person { int m_id; int m_age; int m_height; void display() { cout << "display(),m_id is:" << m_id << endl; cout << "display(),m_age is:" << m_age << endl; cout << "display(),m_height is:" << m_height << endl; } }; Person person; person.m_id = 10; person.m_age = 20; person.m_height = 40; //对象的本质就是成员变量的一块内存 Person *rperson = (Person*)&person.m_age; rperson->m_id = 50; rperson->m_age = 30; //打印:10,50,30 person.display();
-
this
- this是指向当前对象的指针
- 对象在调用成员函数的时候,会自动传入当前对象的内存地址
- 可以利用this.m_age来访问成员变量么?
- 不可以,因为this是指针,必须用this->m_age
- 为什么在调用成员函数时传入当前对象的指针,即this呢?
- 由上面我们知道,对象的内存分配只有成员变量且在栈中;
- 而类的成员函数是统一编译放在代码段的
- 表面上看起来类的成员函数跟对象有什么关联,其实没有任何关联,对象调用成员函数本质就是:
call 函数在代码段编译的地址
- 但是既然成员函数跟对象没有关联,成员函数内部如何访问对象的成员变量呢? 成员函数在代码区,成员变量在栈区
- 只要将对象的栈的首地址在调用成员函数时传入给成员函数,成员函数内部就能拿到相应的成员变量的地址,完成访问了,这就是传入默认this的作用
-
因此,this是依赖于类而存在的!!!(比如:成员函数、构造函数)
struct Person { int m_id; int m_age; int m_height; void display() { cout << "display(),m_age is:" << m_age << endl; //上面访问成员变量的本质如下:默认会给该成员函数传入一个this //cout << "display(),m_age is:" << this->m_age << endl; } }; Person person; person.m_id = 123; person.m_age = 20; person.m_height = 170; //本质:去代码区找到这个函数的地址值,调用这个函数,同时将当前对象的地址值this传给这个函数 person.display();
- 汇编证实:对象调用成员函数时,会将当前对象的指针传给成员函数
-
源码:
Person person; person.m_id = 123; person.m_age = 20; person.m_height = 170; person.display();
-
汇编
//[ebp-14h]是第一个成员变量的地址,也是函数首地址 mov dword ptr [ebp-14h],7Bh mov dword ptr [ebp-10h],14h mov dword ptr [ebp-0Ch],0AAh //将函数首地址保存到ecx寄存器中 lea ecx,[ebp-14h] //调用成员函数,成员函数内部肯定会在ecx寄存器中取值访问 call 002F1456
-