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 的指针;

时间: 2024-12-09 17:44:29

C++构造函数语意学——默认拷贝构造函数的相关文章

C++编译器合成默认构造函数的条件(合成默认拷贝构造函数雷同)

当用户没有为类定义构造函数的时候,编译器并不是为每个类合都成默认的构造函数,只是在编译器需要的时候才合成默认构造函数.编译器合成默认的构造函数只是满足编译器的编译的需要,而不是满足程序员的需要(例如,成员变量的初始化工作还需要程序员来定义构造函数). 1.对象中包含带有默认构造函数的对象 class A{ public: A(); } class B{ public: A a; } 在组合中B需要编译器合成默认的构造函数,来调用A的默认构造函数,来定义(并不帮助程序员初始化)B自己的成员变量,内

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

概述 在 class 中,若程序员没有为该 class object 定义 default constructors,则编译器会根据需要产生一个 implicit default constructor,该 implicit default constructor 被认为是 trivial(无用的).那编译器怎样才能产生一个 nontrivial implicit default constructor?以下四个方面会产生nontrivial implicit default construct

模板类的拷贝构造函数和重载=

http://bbs.csdn.net/topics/190144045 1 #include<iostream> 2 #include<vector> 3 #include<string> 4 5 6 using namespace std; 7 8 template <typename T,size_t size> 9 class fixed_vector 10 { 11 public: 12 typedef T* iterator; 13 typede

C++空类编译器自动生成的6个成员函数、关于构造函数、拷贝构造函数的解释

对于空类,编译器不会生成任何的成员函数,只会生成1个字节的占位符. 有时可能会以为编译器会为空类生成默认构造函数等,事实上是不会的,编译器只会在需要的时候生成6个成员函数:默认构造函数.默认拷贝构造函数.默认析构函数.默认赋值运算符 这四个是我们通常大都知道的.但是除了这四个,还有两个,那就是取址运算符和 取址运算符 const. class Empty { public: Empty(); //缺省构造函数 Empty(const Empty &rhs); //拷贝构造函数 ~Empty();

【C++对象模型】构造函数语意学之二 拷贝构造函数

关于默认拷贝构造函数,有一点和默认构造函数类似,就是编译器只有在[需要的时候]才去合成默认的拷贝构造函数. 在什么时候才是[需要的时候]呢? 也就是类不展现[bitwise copy semantics]时,即不展现[逐位次拷贝]时,才会合成默认拷贝构造函数. 所谓的[逐位次拷贝],也就是简单的赋值,不管类内的数据成员是int还是char*指针,都是简单的赋值,这叫[逐位次拷贝]. 那什么请下不展现[逐位次拷贝]呢? 有四种情况: ①类中有一个类对象成员,而该类对象成员声明了一个默认拷贝构造函数

C++编译器合成默认构造函数和复制控制成员(拷贝构造函数,赋值操作符,析构函数)的条件

(参考自<深入理解C++对象模型>) ”C++新手一般有两个常见的误解: 任何class如果没有定义default constructor,就会被合成一个出来. 编译器合成出来的default constructor会明确设定class 内每一个data member的默认值.” 现在主要解释第一条为什么是错误的,根据<深入理解C++对象模型>,”default constructor 在需要的时候被编译器产生出来”,以下就是4种”需要的时候”: 1). 该类含有一个成员对象而后者

CPP_类默认函数:构造函数,拷贝构造函数,赋值函数和析构函数

类默认函数:构造函数,拷贝构造函数,赋值函数和析构函数 class Person{ public : Person():age(10), name(NULL); Person(int myage, char *myname); Person(const Person &a); ~Person(void); void set_age(int myage); void get_age(void); void set_other_age(Person &a, int b); private: i

《深度探索C++对象模型》第二章 | 构造函数语意学

默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一个成员对象,该成员对象拥有默认构造函数,那么这个类的隐式默认构造函数就是非平凡的,编译器需要为该类合成默认构造函数.为了避免合成出多个默认构造函数,编译器会把合成的默认构造函数.拷贝构造函数.析构函数和赋值拷贝操作符都以内联的方式完成.一个内联含有具有静态链接,不会被文件以外者看到.如果函数不适合做成内联,就

C++构造函数 &amp; 拷贝构造函数 &amp; 派生类的构造函数 &amp; 虚继承的构造函数

构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载.(摘自百度百科构造函数). 一.最基本的构造函数 1 class Base 2 { 3 public: 4 Base(int var) : m_Var(var) 5 { 6 } 7 private: 8 int m_Var; 9 }; 以上构造函数的执行过程: