该系列文章主要整理了C++相关的知识点。对我个人而言,学习C++是为了能阅读理解Android源码里的C++代码,进而理解Android系统为什么要使用C++,并且是如何利用C++实现特定功能的。在Android实战中加深对C++的理解,边学边用,这样学习的效率才是最高的。
C++系列历史文章:
1. 韦东山第4期Android视频-C++快速入门-第1课第1节_c++类的引入-学习笔记
2. 韦东山第4期Android视频-C++快速入门-第2课第1/2节_c++基础知识_访问控制/程序结构-学习笔记
3. 韦东山第4期Android视频-C++快速入门-第2课第3节_c++基础知识_重载_指针_引用-学习笔记
参考:
《韦东山第4期教学视频-Android-C++快速入门-第2课第4节_c++基础知识_构造函数》
《C++语言程序设计(第3版本)》郑莉,大学入门教材,浅显但是有些知识点解释不清楚。
代码*载下**:
06th_constructor目录:https://github.com/wuweidong0107/cpp_projects
一、C++里类的构造和析构函数
构造函数
一个类里可能有多个数据成员,当用类去创建对象的时候,如何快速的初始化对象里的多个数据成员?构造函数就是帮我们做这个事的,示例如下:

构造函数相关的知识点:
- 构造函数名与类名相同,没有返回值;
- 如果类里没写构造函数,编译器会自动生成一个没有参数的构造函数,函数体为空;
- 只要自定义了一个构造函数,编译器就不会自动生成那个没有参数的构造函数;
- 构造函数在对象被创建时自动被调用;
- 构造函数里可以访问类里的所有数据成员;
- 一切成员函数有的特性,构造函数也可以有: 可以是内联函数,可以被重载等;
析构函数
构造函数是为了初始化对象,那么对应的就有一个析构函数来做扫尾工作。最典型的善后工作就是:释放构造函数里申请的资源(一般是内存),示例如下:

运行结果:
Pserson(char*, int)
name = zhangsan, age = 16
~Person()
deleting: name = zhangsan
before test_func
在对象被销毁时,析构函数就会被自动调用。对象在2种情况下会被销毁:
- 通过Person p1方式定义的对象,在脱离其作用域时,对象会自动被销毁;
- 通过 Person* pPer = new Person()方式动态分配的对象,使用delete可将对象手动销毁;
虽然C++会在程序退出时自动释放所有内存,但是如果你的程序是需要长期运行永不退出的话,为了避免内存泄露,就一定要自定义析构函数,并且在构造函数里申请的资源,务必在析构函数中将其释放。
析构函数相关的知识点:
- 1个类只能有1个析构函数;
- 如果类里没写析构函数,编译器会自动生成一个析构函数,函数体为空;
- 析构函数不接受任何参数,没有返回值;
- 析构函数在对象被销毁时被调用;
- new出来的对象,必须手动delete对象才会调用析构函数。如果忘记delete了,那么程序退出时虽然所有内存会被回收,但是对象的析构函数仍然不会被调用。
二、C++里动态分配和释放对象
C++在创建对象有两种方式:Person per1 或者 Person* pPer= new Person(),它们的区别在于:
- 不使用new创建对象时,对象是分配在栈中的,其作用范围只是对象的作用域里,当程序跳出了对象的作用域时,系统就会自动调用析构函数,删除该对象。
- 使用new创建对象时,对象是分配在堆中的,必须要程序员手动的去管理该对象的内存空间,即不用对象时需要手动delete掉,只有手动执行delete对象操作时,析构函数才会被调用。
示例如下:

new相关的知识点:
- 可以将new理解为C++的一个关键字,它的用途就是创建对象;
- 除了可以new对象,也可以new基本类型: int p = new int(2);
- new对象时实际做了三件事:获得内存空间、调用构造函数(基本类型跳过这个步骤)、返回指针;
- new对象时会调用一个函数来获得内存空间,这个函数的名字是operator new,可以重写或重载这个函数来改变它的行为。暂时不需要理解这个知识点,感兴趣可以参考下面这2篇文章。
参考:
https://blog.csdn.net/bbs375/article/details/53202079
https://www.cnblogs.com/slgkaifa/p/6887887.html
new和malloc的区别:
- new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,即为自由存储区。自由存储区不仅可以是堆,还可以是静态存储区,这取决于operator new在哪里为对象分配内存。
- new分配内存成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
- new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
- new和delete时会调用构造函数和析构函数,这里就允许有自定义操作,而malloc和free没有自定义的空间。
- malloc之后如果发现容量不够用,可以用realloc申请更多空间,而new则没有这个功能。
参考:
http://www.codeceo.com/article/cpp-new-malloc-10-tips.html
三、拷贝构造函数
拷贝构造函数
一种特殊的构造函数,其形参是本类的对象的引用。即用一个已经存在的对象,去初始化同类的另外一个对象。如果没有自定义拷贝构造函数,编译系统会自动生成一个默认的拷贝构造函数,默认的拷贝构造函数的功能是将初始值对象的所有数据成员的值赋给新建对象的数据成员,示例如下:

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!
无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。
点击这里找小助理0元领取:加微信领取资料


拷贝构造函数相关的知识点:
- 如果类里没写拷贝构造函数,编译器会自动生成拷贝构造函数,它实现了最基本的值拷贝的操作,这就是所谓的浅拷贝,上述这个person13.cpp就是浅拷贝,per1.name和per2.name共享了"zhangsan"这个字符串常量,在这个demo里虽然说不上是一种错误,但是程序员要理解这意味着什么。
- 与浅拷贝对应的就是深拷贝,深拷贝是为了实现每一个对象的数据成员都有自己的一份数据拷贝。说白了就是每一个对象数据成员都有自己的内存空间,对象之间的数据成员互不干扰。
深拷贝示例:

运行效果:

理解深拷贝就是要记住这一点: 每一个对象数据成员都有自己的内存空间,对象之间的数据成员互不干扰。
拷贝构造函数在以下3种情况下回被调用:
1. 用类的一个对象去初始化另外一个对象时;
Person A("Jack",16);
Person B(A);
2. 如果函数的形参是类的对象,调用该函数进行形参和实参结合时;
void fun(Person A);
main
Person A;
f(A);
3. 如果函数的返回值是类的对象,函数返回时;
Person fun() {
Person A;
return A;
}
main
Point B=fun();
四、类的组合如何初始化对象
类的组合描述的是一个类内嵌其他类的对象作为成员的情况,示例如下:

类的组合相关的知识点:
- 当创建组合类对象时,即本类具有内嵌对象成员,那么各个内嵌对象会首先被自动创建(内嵌对象的构造函数被调用),然后再调用本类的构造函数;
- 当创建组合类对象时,既要对本类的基本类型数据成员进行初始化,又要对内嵌对象成员进行初始化;
- Student(int id, char *f_name, char *m_name, int f_age = 40, int m_age = 39) : mother(m_name, m_age), father(f_name, f_age),通过这种形式可以对内嵌对象进行初始化。mother(m_name, m_age), father(f_name, f_age)被称为初始化列表;
- 对基本类型的数据成员也可以采用初始化列表的形式进行初始化,例如: Person(char *n, int a) : name(n), age(a) {};
- 当需要销毁组合类对象时,会先调用本类的析构函数,再销毁各个内嵌对象(内嵌对象的析构函数被调用);
- 当创建组合类对象时没有指定初始值,那么本类的无参构造函数会被调用,内嵌对象的无参构造函数也会被调用;
- 如何实现组合类的拷贝构造函数,假设C类中含有B类的对象b,那么C类的拷贝构造函数形式=C::C(C &c1):b(c1.b) {...};
五、结语
下一篇的内容:C++基础知识_静态成员_友元
文章链接:https://mp.weixin.qq.com/s/y6iZmKMWDf6Y_UGY5pPXdw
转载自:老吴嵌入式 ,作者吴伟东Jack
文章链接:韦东山Android视频-C++快速入门-第2课第4节_c++基础知识_对象的创建销毁和拷贝