类和对象

◼ C++中可以使用struct、class来定义一个类

◼ struct和class的区别

  • struct的默认成员权限是public

  • class的默认成员权限是private

struct Person {
   // 成员变量(属性)
   int m_age;

   // 成员函数(方法)
   void run() {
      cout << "Person::run() - " << m_age << endl;
   }
};

int main() {
    // 利用类创建对象
    Person person;
    person.m_age = 20;
    person.run();
}

class的默认成员权限是private

class Person {
   // 成员变量(属性)
   int age;

   // 成员函数(方法)
   void run() {
      cout << "Person::run()" << endl;
   }
};
image-20210331204543354
#include <iostream>
using namespace std;

class Person {
public:
   // 成员变量(属性)
   int m_age;

   // 成员函数(方法)
   void run() {
      cout << "Person::run()" << endl;
   }
};
int main(){
    Person person;
    person.m_age = 20;
    
    Person *p = &person;
    p->m_age = 40;
    p->run();
}

◼ 每个人都可以有自己的编程规范,没有统一的标准,没有标准答案,没有最好的编程规范

◼ 变量名规范参考

  • 全局变量:g_
  • 成员变量:m_
  • 静态变量:s_
  • 常量:c_
  • 使用驼峰标识

◼ 可以尝试反汇编struct和class,看看是否有其他区别

class Car {
public:
    int m_price;

    void run() {
        cout << "Car::run() " << m_price << endl;
    }
};
int main() {
    // mov         dword ptr [ebp-8],0Ah
    // mov         dword ptr [ebp-8],0Ah
    Car car;
    car.m_price = 10;
    car.run(); // call 函数地址
}
  • Class
image-20210331205450685
  • Struct
image-20210331205647345
_car$ = -4 ; size = 4
_main PROC
  push ebp
  mov ebp, esp
  push ecx
  mov DWORD PTR _car$[ebp], 10 ; 0000000aH
  lea ecx, DWORD PTR _car$[ebp]
  call void Car::run(void) ; Car::run
  xor eax, eax
  mov esp, ebp
  pop ebp
  ret 0
_main ENDP

通过汇编可以看出,struct和class 在调用处的汇编代码完全一致,可以说明,struct和class唯一的不同,就是权限控制访问不同。

对象的内存布局

#include <iostream>
using namespace std;

struct Person {
   int m_id;
   int m_age;
   int m_height;

   void display() {
      cout << "id = " << m_id 
         << ", age = " << m_age
         << ", height = " << m_height << endl;
   }
};

// 全局区(数据段)
// Person person;

int main() {

   // 这个person对象内存在栈空间
   Person person;
   person.m_id = 1;
   person.m_age = 2;
   person.m_height = 3;

   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;

   return 0;
}

&person == 0x7ffee6844880
&person.m_id == 0x7ffee6844880
&person.m_age == 0x7ffee6844884
&person.m_height == 0x7ffee6844888

◼ 思考:如果类中有多个成员变量,对象的内存又是如何布局的?

image-20210331210950206

this

struct Person {
   // 成员变量(属性)
   int m_age;

   // 成员函数(方法)
   void run() {
      cout << "Person::run() - " << m_age << endl;
   }
};

int main() {
    // 利用类创建对象
    Person person;
    person.m_age = 20;
    person.run();
    
    Person person2;
    person2.m_age = 30;
    person2.run();
}

Person::run() - 20

Person::run() - 30

image-20210331211917773

◼ ==this是指向当前对象的指针==

void Person::run(void) ENDP ; Person::run

_person2$ = -8 ; size = 4
_person$ = -4 ; size = 4
_main PROC
  push ebp
  mov ebp, esp
  sub esp, 8
  mov DWORD PTR _person$[ebp], 20 ; 00000014H
  lea ecx, DWORD PTR _person$[ebp]              ;lea 将ebp-4 的地址值放入ecx
  call void Person::run(void) ; Person::run
  mov DWORD PTR _person2$[ebp], 30 ; 0000001eH
  lea ecx, DWORD PTR _person2$[ebp]             ;lea 将ebp-8 的地址值放入ecx
  call void Person::run(void) ; Person::run
  xor eax, eax
  mov esp, ebp
  pop ebp
  ret 0
_main ENDP

◼ 对象在调用成员函数的时候,会自动传入当前对象的内存地址

将run函数修改一下来看汇编代码

    void run() {
        // this指针存储着函数调用者的地址
        // this指向了函数调用者

        // cout << "Person::run() - " << this->m_age << endl;

        // this->m_age = 3;
        m_age = 3;
        /*
        // ebp-8是this指针的地址
        mov         dword ptr [ebp-8],ecx
        mov         eax,dword ptr [ebp-8]
        mov         dword ptr [eax],3
        */
    }
image-20210331213412924
_this$ = -4 ; size = 4
void Person::run(void) PROC ; Person::run, COMDAT
  push ebp
  mov ebp, esp
  push ecx
  mov DWORD PTR _this$[ebp], ecx
  mov eax, DWORD PTR _this$[ebp]
  mov DWORD PTR [eax], 3
  mov esp, ebp
  pop ebp
  ret 0
void Person::run(void) ENDP ; Person::run

_person2$ = -8 ; size = 4
_person$ = -4 ; size = 4
_main PROC
  push ebp
  mov ebp, esp
  sub esp, 8
  mov DWORD PTR _person$[ebp], 20 ; 00000014H
  lea ecx, DWORD PTR _person$[ebp]
  call void Person::run(void) ; Person::run
  mov DWORD PTR _person2$[ebp], 30 ; 0000001eH
  lea ecx, DWORD PTR _person2$[ebp]
  call void Person::run(void) ; Person::run
  xor eax, eax
  mov esp, ebp
  pop ebp
  ret 0
_main ENDP

可以看出,类函数调用前会将对象的地址放入ecx 然后进入函数调用后,第一条语句,就是把ecx的值给了this变量来存储。

◼ 可以利用this.m_age来访问成员变量么?

  • 不可以,因为this是指针,==必须用this->m_age==

指针访问对象成员的本质

struct Person {
   int m_id;
   int m_age;
   int m_height;

   void display() {
    
      cout << "id = " << m_id
         << ", age = " << m_age
         << ", height = " << m_height << endl;
   }
};


void test() {
    Person person;
    person.m_id = 5;
    
    
    Person *p = &person;
    p->m_id = 10;
    p->m_age = 10;
    p->m_height = 10;
    p->display();
}
image-20210331214720910

来分析这段汇编代码

_p$ = -20 ; size = 4
_person$ = -16 ; size = 12
__$ArrayPad$ = -4 ; size = 4
_main PROC
  push ebp
  mov ebp, esp
  sub esp, 20 ; 00000014H
  mov eax, DWORD PTR ___security_cookie
  xor eax, ebp
  mov DWORD PTR __$ArrayPad$[ebp], eax
  mov DWORD PTR _person$[ebp], 5                ;ebp-16 赋值 5
  lea eax, DWORD PTR _person$[ebp]              ;lea 将_person的地址值给到 eax
  mov DWORD PTR _p$[ebp], eax                   ;将eax的值放入 ebp-20的中 即 Person *p = &person;从上面汇编来看,所以-->说&是取地址
  mov ecx, DWORD PTR _p$[ebp]                   ;将[ebp-20]的值给ecx ecx=&person
  mov DWORD PTR [ecx], 10 ; 0000000aH           ;ecx=&person=10
  mov edx, DWORD PTR _p$[ebp]                   ;将[ebp-20]的值给edx edx=&person
  mov DWORD PTR [edx+4], 10 ; 0000000aH         ;[edx+4]=&person+4=10
  mov eax, DWORD PTR _p$[ebp]
  mov DWORD PTR [eax+8], 10 ; 0000000aH
  mov ecx, DWORD PTR _p$[ebp]
  call void Person::display(void) ; Person::display
  xor eax, eax
  mov ecx, DWORD PTR __$ArrayPad$[ebp]
  xor ecx, ebp
  call @__security_check_cookie@4
  mov esp, ebp
  pop ebp
  ret 0
_main ENDP

从这段汇编代码可以看出,指针访问成员变量,想获取对象的地址,然后通过对象的地址偏移 +0 +4 +8即通过对象的内存布局来直接操作地址来赋值

◼ 思考:==最后打印出来的每个成员变量值是多少?==

struct Person {
   int m_id;
   int m_age;
   int m_height;

   void display() {
    
      cout << "id = " << m_id
         << ", age = " << m_age
         << ", height = " << m_height << endl;
   }
};
int main() {

   Person person;
   person.m_id = 10;
   person.m_age = 20;
   person.m_height = 30;

   Person *p = (Person *) &person.m_age;

   p->m_id = 40;
   p->m_age = 50;

   // 将person对象的地址传递给display函数的this
    person.display();

   return 0;
}

id = 10, age = 40, height = 50

如果将person.display()换成p->display()呢?

    // 会将指针p里面存储的地址传递给display函数的this
    // 将&person.m_age传递给display函数的this
p->display();

id = 40, age = 50, height = 0

image-20210331220657115
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容