一、典型的C++面向对象编程
1、元素
- 头文件hpp中类的定义
- 源文件cpp中类的实现(构造函数、析构函数、方法)
- 主程序
2、实战中,一般一个cpp和一个hpp文件配对,描述一个class,class的名字和文件名相同。
3、面向对象式编程总结
- 整个工作分为2大块:一个是建模和编写类库,一个是使用类库来编写主程序完成任务。
- 有些人只负责建模和编写类库,譬如开发OpenCV的人。
- 有些人直接调用现成类库来编写自己的主任务程序,譬如使用OpenCV分析一张图片中有没有电动车。
- 难度上不确定,2个都有可能很难或很简单。
4、C++学习的三重境界
- 学习C++第一重境界就是语法层面,先学会如何利用C++来建模、来编程,学习语法时先解决难度大问题。
- 学习C++第二重境界就是解决问题层面,学习如何理解并调用现成类库来编写主程序解决问题。
- 学习C++的第三重境界是编写类库和sample给别人用,需要基础好且有一定架构思维。
二、C++的构造函数 和 析构函数
1、什么是构造函数
- constructor,字面意思是用来构造对象的函数;destructor,字面意思是用来析构对象的函数。
- 可以理解为语言自带的一种hook函数(回调函数,满足一定条件下会被自动调用的函数)
- 当对象产生时constructor会被自动调用,一般用于初始化class的属性、分配class内部需要的动态内存。
- 当对象消亡时destructor会被自动调用,一般用于回收constructor中分配的动态内存,避免内存丢失。
2、构造和析构一般用法
- 不写时C++会自动提供默认的构造和析构,也可以显式提供默认构造和析构函数。
- 构造和析构函数不需要返回值类型,构造函数可以带参或不带参,析构函数不带参。
- 构造函数可以重载(overlord),析构函数不需要重载。
3、为什么需要构造函数和析构函数
- 构造函数可以看作是对象的初始化式,注意对比对象和变量的初始化区别。
- 构造函数可以为对象完成动态内存申请,同时在析构函数中再释放,形成动态内存的完整使用循环。
- C语言中struct无构造函数概念,所以struct中需要用到动态内存时必须在定义struct变量后再次单独申请和释放,而这些操作都需要程序员手工完成。
- C++ class的构造和析构特性,是C++支持面向对象编程的一大语言特性。
三、在构造和析构函数中使用动态内存
1、析构函数的使用
- 析构函数在对象销毁时自动调用,一般有以下2种情况
- 用new分配的对象,分配在堆上,用delete显示析构
- 分配在栈上的对象,当栈释放时自动析构
- 普通情况下析构函数都是空的,因为不必做什么特别的事情
2、在class中使用动态内存变量
- 什么情况下用动态内存?需要大块内存,且需要按需灵活的申请和释放,用栈怕爆、用全局怕浪费和死板。
- 在class 中增加一个int* 指针,用于指向一个int类型元素的内存空间。
- 在构造函数中分配动态内存
- 在析构函数中回收动态内存
- 将动态内存从int变量升级到int数组变量
- 实战中C++常用的动态内存往往是容器vector那些,后面会讲到。
3、用valgrind工具查看内存泄漏
- valgrind工具介绍,参考:https://blog.csdn.net/u012662731/article/details/78652651
- 安装:sudo apt-get install valgrind(ubuntu16.04 X64)
- 编译使用:主要是添加-g参数便于调试时有行号 g++ person.cpp main.cpp -g -o apptest
- 使用:valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes ./apptest
四、构造函数与类的成员初始化
1、构造函数一大功能就是初始化成员变量
- 默认构造函数不带参,无初始化功能。
- 若无其他构造函数,则默认构造函数可以省略。但若有哪怕1个其他的构造函数,则默认构造函数不能省略,必须写上。
- 栈上分配对象时,若使用默认构造函数,则对象变量后面不加空的(),若用带参构造才需要加(初始化参数)。
2、C++的成员初始化列表
- 一般用于带参构造函数中,用来给属性传参赋值。
- 成员初始化列表和构造函数之间用冒号间隔,多个列表项之间用逗号间隔。
- 初始化列表可以替代构造函数内的赋值语句,达到同样的效果。
3、构造函数使用参数默认值
- class声明时可以给函数形参赋值一个默认值,实际调用时若不传参就使用默认值。
- 方法实现时形参可以不写默认值,但是实际是按照声明时的默认值规则的。
- 有默认值情况,要注意实际调用不能有重载歧义,否则编译不能通过。
- 所有参数都带默认值的构造函数,1个可以顶多个构造函数。