C++ Day06 面向对象 A struct vs class、栈空间

204 阅读4分钟
1. C++ 中定义一个类有哪两种方法?这两种方法有什么区别?
  • C++ 中可以用 structclass 这两个关键字来定义类
  • 区别:① struct 成员和方法默认权限是 public ② class 成员和方法默认权限是private
2. C++ 编程规范(了解)
  • 每个人都可以有自己的编程规范,没有统一的标准,没有标准答案,没有最好的编程规范。
  • 全局变量:g_
  • 成员变量:m_
  • 静态变量:s_
  • 常量:c_
3. 一个实例对象可以通过 对象指针 访问属性,这两种方法有什么不同?
  • 写法:对象用 .点语法;指针用 ->箭头语法
  • 汇编:对象是拿 首地址 + 偏移量 直接访问;指针是先 拿出指针所存首地址放到寄存器 然后再用 首地址 + 偏移量 访问;
  • 补充:从汇编指令数目来讲,对象访问只需要一条指令,指针访问需要两条指令;所以用对象访问效率会高一些,但是我们通常用指针访问并不是为了提高效率。

// person.age = 10 对应的汇编代码
0x100003f9d <+13>: movl   $0xa, -0x8(%rbp)

// p->age = 15 对应的汇编代码
0x100003fac <+28>: movq   -0x10(%rbp), %rcx
0x100003fb0 <+32>: movl   $0xf, (%rcx)
4. 下面代码,为什么实例对象只占 4 个字节(方法不占空间吗)?
struct People {
 int age;
 void display() {
     age = 1;
 }
};
  • 方法存在代码块,不在实例对象中,实例对象只需存 age 即可,所以只需要 4 个字节。
5. 类实例调用方法,实例的在堆区或者栈区,而方法存储在代码段。那么方法里面的成员变量是怎么知道是哪个对象在调用该方法?
  • 在调用方法的时候,编译器会将调用者做为参数,传递给方法。
0x100003d05 <+53>: movq   -0x18(%rbp), %rdi         // 下面第一句就是把方法调用的地址传递给 rdi;rdi 常常做为函数参数;
0x100003d09 <+57>: callq  0x100003d20               // Student::display at main.cpp:10 方法调用
6. 思考下面代码的输出(领悟指针访问对象的真谛)?
struct Student {
 int age;
 int height;
 int weight;
 void display() {
     cout << age << endl;
     cout << height << endl;
     cout << weight << endl;
 }
};

int main() {
 
 Student student;
 student.age = 10;
 student.height = 20;
 student.weight = 30;
 
 Student *s = (Student *)&(student.height);
 s->age = 40;
 s->height = 50;
 
 // 第一次打印
 student.display();
 
 // 第二次打印
 s->display();
 return 0;
}
  • 第一次打印: 10 40 50
  • 第二次打印: 40 50 未知
7. 怎么理解函数代码存储在代码段,函数调用的时候却在栈空间分配内存?
  • 代码段:只存储了函数对应的汇编指令,而且代码段是只读的
  • 栈空间:在函数调用时,才会真正给局部变量分配内存空间
8. 每个应用之间的内存是独立的吗?四个主要的内存区域依次是哪四个?
  • 每个应用程序的内存空间都是独立的,互不干扰,都是虚拟内存
  • 全局区 → 代码段 → 堆空间 → 栈空间
9. 思考栈空间也能分配空间给对象,那为什么还要堆空间呢?
  • 栈空间的特定:在函数开始时内存由系统自动分配,在函数结束时内存由系统自动回收;
  • 很多情况下我们需要自由控制内存的分配的大小,以及内存的生命周期
10. 在 C++ 中向堆空间申请\释放内存,有哪三种方式?
  • malloc \ free
  • new \ delete
  • new[] \ delete[]
  • 申请堆空间成功后,会返回那一段内存空间的地址
  • 申请和释放必须是 1 对 1 的关系,不然可能会存在内存泄漏
11. 现在很多高级编程语言不需要开发人员去管理内存(比如 Java、OC、Swift),屏蔽了很多内存细节,这样有什么利弊?
  • 利:提高开发效率,避免内存使用不当或泄漏
  • 弊:不利于开发人员了解本质,永远停留在 API 调用和表层语法糖,对性能优化无从下手
12. 如果需要将较大的数据结构(比如对象、数组等)内存清零比较快的方法是什么?memeset(p, 1, 4) 是什么意思?
  • 使用 memset 函数
  • memeset(p, 1, 4) 是将 4 个字节中的每个字节都设置为 1(注意不是将 4 个字节设置为 1
int main() {
 Student s;
 s.age = 10;
 s.height = 10;
 s.weight = 10;
 s.display();
 
 memset(&s, 0, sizeof(s));
 s.display();
 return 0;
}