C++构造函数语意学——默认拷贝构造函数

电玩女神 2022-08-07 03:40 328阅读 0赞

概述

使用 class object 时,在以下三种情况会以一个 object 的内容作为另一个 class object 的初值,即用到拷贝构造函数:

  1. 定义一个 class object 并对其进行初始化;
  2. class object 作为一个参数传递给函数;
  3. class object 作为函数的返回值;

若用户没有显示声明或定义拷贝构造函数,则 C++ 在 必要 时为 class 声明或定义隐式拷贝构造函数,若出现以下的情况时,该拷贝构造函数是 trivial 的:

  1. their class has no virtual functions and no virtual base class(es).
  2. all direct base classes and non-static data members of their class have trivial constructors.
  3. Otherwise, the copy constructor are non-trivial. Implicitly-declared non-trivial copy constructor.

默认拷贝构造函数

在以下四种情况下,编译器会合成一个 non-trivial 的默认拷贝构造函数:

  1. 当 class 内含一个具有 copy constructor 的 member object;
  2. 当 class 继承自一个具有 copy constructor 的 base class;
  3. 当 class 声明有 virtual functions;
  4. 当 class 派生自 virtual base class(es);

前面两种情况,编译器必须将 member 或 base class 的 copy constructor 放置在默认拷贝构造函数中,以下例子同时满足这两个情况:

  1. #include <iostream>
  2. using namespace std;
  3. class Foo {
  4. public:
  5. Foo() {}
  6. Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
  7. };
  8. class Word: public Foo {
  9. public:
  10. int x;
  11. Foo foo;
  12. };
  13. int main()
  14. {
  15. Word ba;
  16. Word bb = ba;
  17. return 0;
  18. }

执行结果:编译器在合成的拷贝构造函数中调用了两次 Foo 类的拷贝构造函数;

  1. (gdb) r
  2. Starting program: ./test02
  3. Breakpoint 1, main () at test02.cpp:20
  4. 20 Word ba;
  5. (gdb) s
  6. Word::Word (this=0xbffff020) at test02.cpp:11
  7. 11 class Word: public Foo {
  8. (gdb) s
  9. Foo::Foo (this=0xbffff020) at test02.cpp:7
  10. 7 Foo() {}
  11. (gdb) s
  12. Foo::Foo (this=0xbffff024) at test02.cpp:7
  13. 7 Foo() {}
  14. (gdb) s
  15. main () at test02.cpp:21
  16. 21 Word bb = ba;
  17. (gdb) s
  18. Word::Word (this=0xbffff028) at test02.cpp:11
  19. 11 class Word: public Foo {
  20. (gdb) s
  21. Foo::Foo (this=0xbffff028, foo=...) at test02.cpp:8
  22. 8 Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
  23. (gdb) s
  24. Foo's copy construct!
  25. Foo::Foo (this=0xbffff02c, foo=...) at test02.cpp:8
  26. 8 Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
  27. (gdb) s
  28. Foo's copy construct!
  29. main () at test02.cpp:22
  30. 22 return 0;
  31. (gdb) s
  32. 23 }
  33. (gdb)

第三种情况,若是相同 class 的 object 直接的初始化,可以采用 bitwise copy 方式进行,因为 vptr 指向相同的虚函数表;若是使用派生类 object 初始化 基类 object 时,则编译器会重新设定 class object 的 virtual table 的指针,因为不同类的 vptr 指向各自的虚函数表;

  1. #include <iostream>
  2. using namespace std;
  3. class Foo {
  4. public:
  5. virtual void func()
  6. { cout << "virtual function in Foo!" << endl; }
  7. };
  8. class Word: public Foo {
  9. public:
  10. void func()
  11. { cout << "virtual function in Word!" << endl; }
  12. };
  13. int main()
  14. {
  15. Word b1;
  16. Word b2 = b1; // 相同类对象之间初始化,vptr直接复制,指向相同的virtual function table
  17. b2.func();
  18. Foo foo = b1; // 不同类对象之间初始化,发生切割,vptr不直接复制,指向不同的virtual function table
  19. foo.func();
  20. return 0;
  21. }

执行结果:

  1. (gdb) b 19
  2. Breakpoint 1 at 0x8048809: file test03.cpp, line 19.
  3. (gdb) r
  4. Starting program: /home/nifengweijifen/linuxStudy/ObjectModel/chap02/test03
  5. Breakpoint 1, main () at test03.cpp:19
  6. 19 Word b1;
  7. (gdb) s
  8. Word::Word (this=0xbffff024) at test03.cpp:12
  9. 12 class Word: public Foo {
  10. (gdb) s
  11. Foo::Foo (this=0xbffff024) at test03.cpp:6
  12. 6 class Foo {
  13. (gdb) s
  14. main () at test03.cpp:20
  15. 20 Word b2 = b1; //相同类之间的初始化,直接复制 vptr,指向相同的virtual function table
  16. (gdb) s
  17. Word::Word (this=0xbffff028) at test03.cpp:12
  18. 12 class Word: public Foo {
  19. (gdb) s
  20. Foo::Foo (this=0xbffff028) at test03.cpp:6
  21. 6 class Foo {
  22. (gdb) s
  23. main () at test03.cpp:21
  24. 21 b2.func();
  25. (gdb) s
  26. Word::func (this=0xbffff028) at test03.cpp:15
  27. 15 { cout << "virtual function in Bar!" << endl; }
  28. (gdb) s
  29. virtual function in Word!
  30. main () at test03.cpp:23
  31. 23 Foo foo = b1; // 不同类之间的初始化,发生切割,vptr不直接复制,指向不同的virtual function table
  32. (gdb) s
  33. Foo::Foo (this=0xbffff02c) at test03.cpp:6
  34. 6 class Foo {
  35. (gdb) s
  36. main () at test03.cpp:24
  37. 24 foo.func();
  38. (gdb) s
  39. Foo::func (this=0xbffff02c) at test03.cpp:9
  40. 9 { cout << "virtual function in Foo!" << endl; }
  41. (gdb) s
  42. virtual function in Foo!
  43. main () at test03.cpp:25
  44. 25 return 0;
  45. (gdb) s
  46. 26 }
  47. (gdb)

第四种情况和第三种情况相似,若是相同 class 的 object 直接的初始化,可以采用 bitwise copy 方式进行;若是使用派生类 object 初始化 基类 object 时,则编译器会重新设定 virtual base class 的指针;

发表评论

表情:
评论列表 (有 0 条评论,328人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++拷贝构造函数

    最近在复习C++的考试,对于上机中出现多的是构造函数\\拷贝构造函数\\虚函数等等接触了很多,对它们的理解逐步的加深. . 什么是拷贝构造函数 首