当前位置:编程学习 > C/C++ >>

C++构造函数和拷贝构造函数详解

 

  构造函数、析构函数与赋值函数是每个类最基本的函数。它们太普通以致让人容易麻痹大意,其实这些貌似简单的函数就象没有顶盖的下水道那样危险。

 

每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数)。

 

对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A 产生四个缺省的函数,例如:

 

        A(void); // 缺省的无参数构造函数

 

        A(const A &a); // 缺省的拷贝构造函数

 

        ~A(void); // 缺省的析构函数

 

        A & operate =(const A &a); // 缺省的赋值函数

 

这不禁让人疑惑,既然能自动生成函数,为什么还要程序员编写?原因如下:

 

       <1>如果使用“缺省的无参数构造函数”和“缺省的析构函数”,等于放弃了自主“初始化”和“清除”的机会,C++发明人Stroustrup 的好心好意白费了。

 

       <2>“缺省的拷贝构造函数”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝”的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。

 

C++ 默认构造函数 :

 

1、每个类必须有一个构造函数,否则没法创建对象;

2、若 程序员没有提供任何构造函数,则C++提供一个默认的构造函数,该默认构造函数是无参构造函数,它仅负责创建对象,不做任何初始化的工作;

3、只要programer 定义了一个构造函数(不管是无参还是有参构造),C++就不再提供默认的默认构造函数。即如果为类定义了一个带参的构造函数,还想要无参构造函数,就必须自己定义;

4、与变量定义类似,在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象的位模式全为0,否则,对象值是随机的。

 

C++默认拷贝构造函数:

1、默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.

2、拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.

3、如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.

4、如果数据成员是一个数组,对数组的每一个执行按位拷贝.

5、如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.

 

请看下面代码:

 

//============================================================================ 

// Name        : main.cpp 

// Author      : ShiGuang 

// Version     : 

// Copyright   : sg131971@qq.com 

// Description : Hello World in C++, Ansi-style 

//============================================================================ 

 

#include <iostream> 

#include <string> 

using namespace std; 

 

class Student 

public: 

    Student() 

    { 

        cout << "构造函数1" << endl; 

    } 

    Student(int k) 

    { 

        cout << "构造函数2" << endl; 

        i = k; 

    } 

    Student(Student const &m) 

    { 

        cout << "拷贝构造函数" << endl; 

        i = m.i * (-1); 

    } 

 

    void p() 

    { 

        cout << i << endl; 

    } 

    ~Student() 

    { 

        cout << "析构函数" << endl; 

    } 

protected: 

    int i; 

}; 

 

int main(int argc, char **argv) 

    Student s(9818); 

    // 调用构造函数2 

    s.p(); 

 

    Student t(s); 

    // 调用拷贝构造函数 

    t.p(); 

 

    Student k = s; 

    // 调用拷贝构造函数 

    k.p(); 

 

    Student *p = new Student(s); 

    // 调用拷贝构造函数 

    p->p(); 

 

    Student m; 

    // 调用构造函数1 

    m = s;// 赋值运算 

    m.p(); 

 

    return 0; 

运行结果:

 

构造函数2 

9818 

拷贝构造函数 

-9818 

拷贝构造函数 

-9818 

拷贝构造函数 

-9818 

构造函数1 

9818 

析构函数 

析构函数 

析构函数 

析构函数 

下面我们来讨论一下关于浅拷贝和深拷贝的问题。

 

        深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候(复制指针所指向的值),这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源(只复制了指针所指的地址)的情况视为浅拷贝。

  很多人会问到,既然系统会自动提供一个默认的拷贝构造函数来处理复制,那么我们没有必要去自定义拷贝构造函数呀,对,就普通情况而言这的确是没有必要的,但在某些状况下,类体内的成员是需要开辟动态堆内存的,如果我们不自定义拷贝构造函数而让系统自己处理,那么就会导致堆内存的所属权产生混乱。试想一下,已经开辟的一端堆地址原来是属于对象a的,由于复制过程发生,b对象取得是a已经开辟的堆地址,一旦程序产生析构,释放堆的时候,计算机不清楚这段地址是真正属于谁的,当连续发生两次析构的时候就出现了运行错误。

  为了更详细的说明问题,请看如下的代码。

 

 

//============================================================================ 

// Name        : main.cpp 

// Author      : ShiGuang 

// Version     : 

// Copyright   : sg131971@qq.com 

// Description : Hello World in C++, Ansi-style 

//============================================================================ 

 

#include <iostream> 

#include <string> 

using namespace std; 

 

class aa 

public: 

    aa() 

    { 

        cout << "调用构造函数" << endl; 

        f = new char[10]; 

    } 

    ~aa() 

    { 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,