• 对象的构造和析构


    目录

    构造函数和析构函数

    构造函数的分类和调用

    c++默认构造的函数

    浅拷贝和深拷贝

    多个对象的构造和析构

    初始化列表

    类对象作为成员


    构造函数和析构函数

    对象的初始化和清理是两个非常重要的安全问题,一个对象或者变量没有初始时,对其使用后果是未知,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题。c++为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和对象清理工作。
    构造函数主要作用在于 创建对象 时为对象的成员属性赋值
    析构函数主要用于 对象销毁 前系统自动调用,执行一些清理工作。
    1. #include
    2. #include
    3. using namespace std;
    4. class function
    5. {
    6. public:
    7. //构造函数 函数名和类名相同,没有返回值,不能有void,但可以有参数 可以重载
    8. function(int init_age,string init_name)
    9. {
    10. age = init_age;
    11. name = init_name;
    12. cout << "构造函数调用" << endl;
    13. }
    14. //析构函数 函数名是在类名前面加”~”组成,没有返回值,不能有void,不能有参数,不能重载
    15. ~function()
    16. {
    17. cout << "析构函数调用" << endl;
    18. }
    19. public:
    20. int age;
    21. string name;
    22. };
    23. void test()
    24. {
    25. function p1(10,"lucy");//构造函数在实例化对象时会创建,就是在内存开辟空间时会被调用
    26. //定义在栈区 test生命周期结束后会被销毁 在销毁之前自动调用析构函数
    27. }
    28. int main()
    29. {
    30. test();
    31. return 0;
    32. }

    编译运行

    构造函数的分类和调用

    按参数类型:分为无参构造函数和有参构造函数

    按类型分类:普通构造函数和拷贝构造函数(复制构造函数)

    拷贝构造:拷贝构造的调用时机:旧对象初始化新对象

                      其形参必须是引用,但并不限制为const,一般普遍的会加上const限制

                      如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造

    1. #include
    2. #include
    3. using namespace std;
    4. class function
    5. {
    6. public:
    7. function()
    8. {
    9. cout << "无参构造函数" << endl;
    10. }
    11. function(int init_age,string init_name)
    12. {
    13. age = init_age;
    14. name = init_name;
    15. cout << "有参构造函数" << endl;
    16. }
    17. //拷贝构造的调用时机:旧对象初始化新对象
    18. //如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造
    19. function(const function &p)//不能写function p 不能产生新对象
    20. {
    21. //拷贝构造做了简单的值拷贝
    22. age = p.age;
    23. name = p.name;
    24. cout << "拷贝构造" << endl;
    25. }
    26. ~function()
    27. {
    28. cout << "析构" << endl;
    29. }
    30. public:
    31. int age;
    32. string name;
    33. };
    34. void test01()
    35. {
    36. //如果人为提供了一个有参或无参构造 系统将不再提供默认的无参构造
    37. function p1;//调用无参构造时 不能加括号
    38. function p2(10,"lucy");
    39. function p3(p2);//调用系统提供的默认拷贝构造
    40. }
    41. void test02()
    42. {
    43. //匿名对象 没有名字 生命周期在当前行
    44. function (10,"tom");
    45. function ();
    46. function p1(20,"ben");
    47. //function p2(p); //匿名对象不能使用括号法调用拷贝函数
    48. }
    49. //显示法调用构造函数
    50. void test03()
    51. {
    52. function p1 = function (10,"tom");//显示法调用有参函数
    53. function p2 = function (p1); //显示法调用拷贝函数
    54. function p3 = function ();//显示法调用无参函数
    55. }
    56. int main()
    57. {
    58. test();
    59. return 0;
    60. }

    c++默认构造的函数

    默认情况下,c++编译器至少为我们写的类增加 3 个函数

    1.默认构造函数(无参,函数体为空)

    2.默认析构函数(无参,函数体为空)

    3.默认拷贝构造函数,对类中非静态成员属性简单值拷贝

    如果用户定义拷贝构造函数, c++ 不会再提供任何默认构造函数
    如果用户定义了普通构造 ( 非拷贝 ) c++ 不在提供默认无参构造,但是会提供默认拷贝构造

    浅拷贝和深拷贝

    浅拷贝:同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况 被称为浅拷贝. 一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动 态内存释放的处理,会导致内存问题。

    深拷贝:当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间。

    1. class Person{
    2. public:
    3. Person(char* name,int age){
    4. pName = (char*)malloc(strlen(name) + 1);
    5. strcpy(pName,name);
    6. mAge = age;
    7. }
    8. //增加拷贝构造函数
    9. Person(const Person& person){
    10. pName = (char*)malloc(strlen(person.pName) + 1);//重新开辟空间
    11. strcpy(pName, person.pName);
    12. mAge = person.mAge;
    13. }
    14. ~Person(){
    15. if (pName != NULL){
    16. free(pName);
    17. }
    18. }
    19. private:
    20. char* pName;
    21. int mAge;
    22. };
    23. void test(){
    24. Person p1("Edward",30);
    25. //用对象 p1 初始化对象 p2,调用 c++提供的默认拷贝构造函数
    26. Person p2 = p1;
    27. }

    多个对象的构造和析构

    初始化列表

    构造函数和其他函数不同,除了有名字,参数列表,函数体之外还有初始化列表。
    初始化列表简单使用 :
    class Person{
    public :
            //传统方式初始化
            Person(int a,int b,int c)
            {
            mA = a;
            mB = b;
            mC = c;
            }
            //初始化列表方式初始化
            //先声明再根据声明的顺序定义初始化
            Person( int a, int b, int c):mA(a),mB(b),mC(c){}
            void PrintPerson()
            {
            cout << "mA:" << mA << endl;
            cout << "mB:" << mB << endl;
            cout << "mC:" << mC << endl;
            }
            private :
            int mA;
            int mB;
            int mC;
    };

    类对象作为成员

    类中有多个对象时,构造的顺序是先构造里面的对象,再构造外面的对象

    类中有多个对象时,析构的顺序是先析构外面的对象,再析构外面的对象

    1. class Car{
    2. public:
    3. Car(){
    4. cout << "Car 默认构造函数!" << endl;
    5. mName = "大众汽车";
    6. }
    7. Car(string name){
    8. cout << "Car 带参数构造函数!" << endl;
    9. mName = name;
    10. }
    11. ~Car(){
    12. cout << "Car 析构函数!" << endl;
    13. }
    14. public:
    15. string mName;
    16. };
    17. //拖拉机
    18. class Tractor{
    19. public:
    20. Tractor(){
    21. cout << "Tractor 默认构造函数!" << endl;
    22. mName = "爬土坡专用拖拉机";
    23. }
    24. Tractor(string name){
    25. cout << "Tractor 带参数构造函数!" << endl;
    26. mName = name;
    27. }
    28. ~Tractor(){
    29. cout << "Tractor 析构函数!" << endl;
    30. }
    31. public:
    32. string mName;
    33. };
    34. //人类
    35. class Person{
    36. public:
    37. //类 mCar 不存在合适的构造函数
    38. Person(string name){
    39. mName = name;
    40. }
    41. //初始化列表可以指定调用构造函数
    42. Person(string carName, string tracName, string name) : mTractor(tracName),
    43. mCar(carName), mName(name){
    44. cout << "Person 构造函数!" << endl;
    45. }
    46. #endif
    47. void GoWorkByCar(){
    48. cout << mName << "开着" << mCar.mName << "去上班!" << endl;
    49. }
    50. void GoWorkByTractor(){
    51. cout << mName << "开着" << mTractor.mName << "去上班!" << endl;
    52. }
    53. ~Person(){
    54. cout << "Person 析构函数!" << endl;
    55. }
    56. private:
    57. string mName;
    58. Car mCar;
    59. Tractor mTractor;
    60. };
    61. void test(){
    62. //Person person("宝马", "东风拖拉机", "赵四");
    63. Person person("刘能");
    64. person.GoWorkByCar();
    65. person.GoWorkByTractor();
    66. }

  • 相关阅读:
    Mac环境下反编译工具的使用
    两岁的娃,要不要上托班?看完你不用再纠结
    【MindSpore Profiler】【性能调优】GPU分布式训练卡死
    Matplotlib 是一个广泛用于 Python 数据可视化的库
    包管理工具cnpm的安装和使用
    三方系统多渠道多场景的思考及代码分享
    java计算机毕业设计响应式交友网站源码+系统+mysql数据库+lw文档+部署
    python opencv环境配置 保姆级教程
    重生奇迹MU中物品拾取的问题
    数据分析 — Pandas 数据加载、存储和清洗
  • 原文地址:https://blog.csdn.net/2301_77164542/article/details/132754037