• 浅谈C++|构造.析构函数篇



    一对象的初始化和处理

    1.1构造函数和析构函数

    C++拥有构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器提供的构造函数和析构函数是空实现。

    ·构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

    ·析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

    语法:

    构造函数语法:类名(){}

      1.构造函数,没有返回值也不写void

      2.函数名称与类名相同

      3.构造函数可以有参数,因此可以发生重载

      4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

    析构函数语法:~类名(){}

      1.析构函数,没有返回值也不写void

      2.函数名称与类名相同,在称前加上符号

      3.析构函数不可以有参数,因此不可以发生重载

      4.程序在对象销毁前会自动调用析构,

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. person() {
    6. cout << "person 构造函数调用" << endl;
    7. }
    8. ~person() {
    9. cout << "person 析构函数调用" << endl;
    10. }
    11. };
    12. void func() {
    13. person a;
    14. }
    15. int main() {
    16. func();
    17. return 0;
    18. }

     1.2构造函数的分类和调用

    两种分类方式:

      按参数分为:有参构造和无参构造

      按类型分为:普通构造和拷贝构造

    三种调用方式:

      括号法

      显示法

      隐式转换发

    1.2.1构造函数分类

    (1)有参和无参构造函数

    代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. person() {
    6. cout << "person 无参构造函数调用" << endl;
    7. }
    8. person(int a) {
    9. cout << "person 有参构造函数调用" << endl;
    10. }
    11. ~person() {
    12. cout << "person 析构函数调用" << endl;
    13. }
    14. };
    15. void func() {
    16. person a(1);
    17. }
    18. int main() {
    19. func();
    20. return 0;
    21. }

    (2)普通和拷贝构造函数 

     代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. person() {
    7. cout << "person的普通构造函数" << endl;
    8. }
    9. person(const person& p) {
    10. age = p.age;
    11. //可以将传入的人的所有属性,拷贝到神上
    12. cout << "person的拷贝构造函数" << endl;
    13. }
    14. };
    15. void func() {
    16. //1.括号法
    17. person p1;
    18. p1.age = 10;
    19. person p2(p1);
    20. cout << p2.age << endl;
    21. }
    22. int main() {
    23. func();
    24. return 0;
    25. }

    1.2.2构造函数的调用方式

    括号法

    显示法

    隐式转换发

    (1)括号法:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. person() {
    7. cout << "person的普通构造函数" << endl;
    8. }
    9. person(int a) {
    10. age = a;
    11. cout << "person的普通构造函数" << endl;
    12. }
    13. person(const person& p) {
    14. age = p.age;
    15. //可以将传入的人的所有属性,拷贝到神上
    16. cout << "person的拷贝构造函数" << endl;
    17. }
    18. };
    19. void func() {
    20. //1.括号法
    21. person p1; //默认
    22. p1.age = 10;
    23. person p2(20); //有参
    24. person p3(p1); //拷贝
    25. //2.
    26. }
    27. int main() {
    28. func();
    29. return 0;
    30. }

    注意: person p() 会被认为是函数声明,并不是调用默认构造

    (2)显示法:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. person() {
    7. cout << "person的普通构造函数" << endl;
    8. }
    9. person(int a) {
    10. age = a;
    11. cout << "person的普通构造函数" << endl;
    12. }
    13. person(const person& p) {
    14. age = p.age;
    15. //可以将传入的人的所有属性,拷贝到神上
    16. cout << "person的拷贝构造函数" << endl;
    17. }
    18. };
    19. void func() {
    20. //2.显示法
    21. person p1; //默认
    22. p1.age = 10;
    23. person p2=person(20); //有参
    24. person p3=person(p1); //拷贝
    25. //2.
    26. }
    27. int main() {
    28. func();
    29. return 0;
    30. }

    1.person(20)称为匿名对象,当前行执行后系统会立即回收匿名对象

    2.不要用拷贝构造函数初始化匿名对象,person(p3) ->person  p3;相当于重新定义一个p3,发生重定义错误。

    (3) 隐式转换法:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. person() {
    7. cout << "person的普通构造函数" << endl;
    8. }
    9. person(int a) {
    10. age = a;
    11. cout << "person的普通构造函数" << endl;
    12. }
    13. person(const person& p) {
    14. age = p.age;
    15. //可以将传入的人的所有属性,拷贝到神上
    16. cout << "person的拷贝构造函数" << endl;
    17. }
    18. };
    19. void func() {
    20. //3.隐式转换发
    21. person p1; //默认
    22. person p2=10; //相当于person p2=person(10);
    23. person p3 = p2; //相当于person p3 = person(p2);
    24. }
    25. int main() {
    26. func();
    27. return 0;
    28. }

    1.3拷贝构造函数调用时机

    1.使用一个已经创建完毕的对象来初始化一个新对象。

    2.值传递的方式给函数参数传值

    3.以值方式返回局部对象

     1.3.1旧对象创建新对象

    代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int b;
    7. person() {
    8. cout << "person的无参构造函数" << endl;
    9. }
    10. person(int a1) {
    11. a = a1;
    12. cout << "person的有参构造函数" << endl;
    13. }
    14. person(const person &p) {
    15. a = p.a;
    16. cout << "person的拷贝构造函数" << endl;
    17. }
    18. ~person() {
    19. cout << "person的析构函数" << endl;
    20. }
    21. };
    22. void fun() {
    23. person A(10);
    24. person B(A);
    25. cout << B.a << ' ' << B.b << endl;
    26. }
    27. int main() {
    28. fun();
    29. return 0;
    30. }

     1.3.2值传递的方式给函数参数传值

    作为函数值传递时,只会复制拷贝函数中已将定义要拷贝的变量,其余的即使已经外部定义了,只要拷贝函数中没有指明要拷贝,形参就不会拷贝。

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int b;
    7. int c;
    8. person() {
    9. cout << "person的无参构造函数" << endl;
    10. }
    11. person(int a1) {
    12. a = a1;
    13. cout << "person的有参构造函数" << endl;
    14. }
    15. person(const person &p) {
    16. a = p.a;
    17. cout << "person的拷贝构造函数" << endl;
    18. }
    19. ~person() {
    20. cout << "person的析构函数" << endl;
    21. }
    22. };
    23. void fun(person A) {
    24. cout << A.a << ' ' << A.b <<' '<
    25. }
    26. int main() {
    27. person A(10);
    28. A.b = 90;
    29. cout << A.a << ' ' << A.b << ' ' << A.c << endl;
    30. fun(A);
    31. return 0;
    32. }

    1.3.3以值方式返回局部对象

    同做做参数一样,也只复制拷贝函数中定义要复制的部分,并不是完全复制。

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int b;
    7. int c;
    8. person() {
    9. cout << "person的无参构造函数" << endl;
    10. }
    11. person(int a1) {
    12. a = a1;
    13. cout << "person的有参构造函数" << endl;
    14. }
    15. person(const person &p) {
    16. a = p.a;
    17. cout << "person的拷贝构造函数" << endl;
    18. }
    19. ~person() {
    20. cout << "person的析构函数" << endl;
    21. }
    22. };
    23. person fun() {
    24. person A(10);
    25. A.b = 90;//已经赋值,但是形参还是随机值
    26. cout << A.a << ' ' << A.b << ' ' << A.c << endl;
    27. return A;
    28. }
    29. int main() {
    30. person A=fun();
    31. cout << A.a << ' ' << A.b << ' ' << A.c << endl;
    32. return 0;
    33. }

     1.4构造函数调用规则

    默认情况下,c++编译器至少给一个类添加3个函数

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

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

    3.默认拷贝构造函数,对属性进行值拷贝(全部)

    构造函数调用规则如下:

    1.如果用户定义有参构造函数,c+不在提供默认无参构造,但是会提供默认拷贝构造

    2.如果用户定义拷贝构造函数,C++不会再提供其他构造函数

    代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int b;
    7. int c;
    8. person(int a1) {
    9. a = a1;
    10. cout << "person的有参构造函数" << endl;
    11. }
    12. ~person() {
    13. cout << "person的析构函数" << endl;
    14. }
    15. };
    16. person fun() {
    17. person A(10);
    18. A.b = 90;
    19. //person B; 报错
    20. return A;
    21. }
    22. int main() {
    23. fun();
    24. return 0;
    25. }

    1.5深拷贝和浅拷贝

    浅拷贝就是简单的赋值操作,深拷贝就是

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int* b;
    7. person(int a1, int b2) {
    8. a = a1;
    9. b = new int(b2);
    10. }
    11. person(const person &p) { //浅拷贝
    12. a = p.a;
    13. b = p.b;
    14. }
    15. ~person() { //浅拷贝
    16. if (b != NULL) {
    17. delete b;
    18. b = NULL;
    19. }
    20. }
    21. };
    22. void fun() {
    23. person a(10,90);
    24. person b(a);
    25. cout << b.a << ' ' << *b.b << endl;
    26. }
    27. int main() {
    28. fun();
    29. return 0;
    30. }

     此时代码会报错,因为此时有两个析构函数,因此会是否两次相同地址的空间,此时要改为深拷贝。

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int* b;
    7. person(int a1, int b2) {
    8. a = a1;
    9. b = new int(b2);
    10. }
    11. person(const person &p) { //深拷贝
    12. a = p.a;
    13. b = new int(*(p.b));
    14. }
    15. ~person() {
    16. if (b != NULL) {
    17. delete b;
    18. b = NULL;
    19. }
    20. }
    21. };
    22. void fun() {
    23. person a(10,90);
    24. person b(a);
    25. cout << b.a << ' ' << *b.b << endl;
    26. }
    27. int main() {
    28. fun();
    29. return 0;
    30. }

     

      1.6初始化列表

    C++提供了初始化列表语法,用来初始化属性。

     语法:构造函数()  :  属性值1(值1),属性值2(值2)....... { }

    代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. int b;
    7. int c;
    8. person(int a1,int b1,int c1) :a(a1), b(b1), c(c1) { //初始化列表
    9. }
    10. };
    11. void fun() {
    12. person p(30, 3,78);
    13. cout << p.a << ' ' << p.b << ' ' << p.c << endl;
    14. }
    15. int main() {
    16. fun();
    17. return 0;
    18. }

  • 相关阅读:
    lua基本语法
    让工程师拥有一台“超级”计算机——字节跳动客户端编译加速方案
    MFC 使用 Imm 类库实现输入法修改输入模式的技术文档
    【C++】C++基础知识(一)---基本概念
    帝国竞争算法(ICA)(Matlab代码实现)
    文字处理工具 word 2019 mac中文版改进功能
    vue3---watch侦听器总结太到位了!
    R语言—基本数据管理
    说说Pluma插件管理框架
    SpringCloudAlibaba的nacos控制台不断输出日志
  • 原文地址:https://blog.csdn.net/m0_73731708/article/details/132927211