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

概述

使用 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 放置在默认拷贝构造函数中,以下例子同时满足这两个情况:

#include <iostream>

using namespace std;

class Foo {
public:
    Foo() {}
    Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
};

class Word: public Foo {
public:

    int x;
    Foo foo;
};

int main()
{
    Word ba;
    Word bb = ba;
    return 0;
}

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

(gdb) r
Starting program: ./test02 

Breakpoint 1, main () at test02.cpp:20
20      Word ba;
(gdb) s
Word::Word (this=0xbffff020) at test02.cpp:11
11  class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff020) at test02.cpp:7
7       Foo() {}
(gdb) s
Foo::Foo (this=0xbffff024) at test02.cpp:7
7       Foo() {}
(gdb) s
main () at test02.cpp:21
21      Word bb = ba;
(gdb) s
Word::Word (this=0xbffff028) at test02.cpp:11
11  class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff028, foo=...) at test02.cpp:8
8       Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
(gdb) s
Foo's copy construct!
Foo::Foo (this=0xbffff02c, foo=...) at test02.cpp:8
8       Foo(const Foo &foo) { cout << "Foo's copy construct!" << endl; }
(gdb) s
Foo's copy construct!
main () at test02.cpp:22
22      return 0;
(gdb) s
23  }
(gdb) 

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

#include <iostream>

using namespace std;

class Foo {
public:
    virtual void func()
    { cout << "virtual function in Foo!" << endl; }
};

class Word: public Foo {
public:
    void func()
    { cout << "virtual function in Word!" << endl; }
};
int main()
{
    Word b1;
    Word b2 = b1;    // 相同类对象之间初始化,vptr直接复制,指向相同的virtual function table
    b2.func();

    Foo foo = b1;   // 不同类对象之间初始化,发生切割,vptr不直接复制,指向不同的virtual function table
    foo.func();
    return 0;
}

执行结果:

(gdb) b 19
Breakpoint 1 at 0x8048809: file test03.cpp, line 19.
(gdb) r
Starting program: /home/nifengweijifen/linuxStudy/ObjectModel/chap02/test03 

Breakpoint 1, main () at test03.cpp:19
19      Word b1;
(gdb) s
Word::Word (this=0xbffff024) at test03.cpp:12
12  class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff024) at test03.cpp:6
6   class Foo {
(gdb) s
main () at test03.cpp:20
20      Word b2 = b1; //相同类之间的初始化,直接复制 vptr,指向相同的virtual function table
(gdb) s
Word::Word (this=0xbffff028) at test03.cpp:12
12  class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff028) at test03.cpp:6
6   class Foo {
(gdb) s
main () at test03.cpp:21
21      b2.func();
(gdb) s
Word::func (this=0xbffff028) at test03.cpp:15
15      { cout << "virtual function in Bar!" << endl; }
(gdb) s
virtual function in Word!
main () at test03.cpp:23
23      Foo foo = b1; // 不同类之间的初始化,发生切割,vptr不直接复制,指向不同的virtual function table
(gdb) s
Foo::Foo (this=0xbffff02c) at test03.cpp:6
6   class Foo {
(gdb) s
main () at test03.cpp:24
24      foo.func();
(gdb) s
Foo::func (this=0xbffff02c) at test03.cpp:9
9       { cout << "virtual function in Foo!" << endl; }
(gdb) s
virtual function in Foo!
main () at test03.cpp:25
25      return 0;
(gdb) s
26  }
(gdb) 

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

你可能感兴趣的:(C++,拷贝构造函数,C++对象模型)