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

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

对于任意一个类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,那么调用系统内建的赋值运算符对其进行赋值.

请看下面代码:

#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

拷贝构造函数
-
拷贝构造函数
-
拷贝构造函数
-
构造函数1 析构函数
析构函数
析构函数
析构函数

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

深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候(复制指针所指向的值),这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源(只复制了指针所指的地址)的情况视为浅拷贝。
  很多人会问到,既然系统会自动提供一个默认的拷贝构造函数来处理复制,那么我们没有必要去自定义拷贝构造函数呀,对,就普通情况而言这的确是没有必要的,但在某些状况下,类体内的成员是需要开辟动态堆内存的,如果我们不自定义拷贝构造函数而让系统自己处理,那么就会导致堆内存的所属权产生混乱。试想一下,已经开辟的一端堆地址原来是属于对象a的,由于复制过程发生,b对象取得是a已经开辟的堆地址,一旦程序产生析构,释放堆的时候,计算机不清楚这段地址是真正属于谁的,当连续发生两次析构的时候就出现了运行错误。
  为了更详细的说明问题,请看如下的代码。

#include <iostream>
#include <string>
using namespace std; class aa
{
public:
aa()
{
cout << "调用构造函数" << endl;
f = new char[];
}
~aa()
{
cout << "调用析构函数" << endl;
delete[] f;
}
char * f;
}; int main(int argc, char **argv)
{
aa p;
printf("p.f=%p\n",p.f);
strcpy(p.f, "Computer");
cout << p.f << endl;
aa q(p);// 调用默认的拷贝构造函数
printf("q.f=%p\n",q.f);
cout << q.f << endl; strcpy(p.f, "Software");
cout << p.f << endl;
cout << q.f << endl; strcpy(q.f, "Software");
cout << p.f << endl;
cout << q.f << endl; return ;
}

运行结果:

调用构造函数
p.f=003F1048
Computer
q.f=003F1048
Computer
Software
Software
Software
Software
调用析构函数
调用析构函数

通过上面的例子,我们能清楚的看到,第二个对象调用拷贝构造函数,q.f获得的地址值与p.f相同,即指向了同一片内存区域。程序结束时,会两次调用析构函数,即同一个指针执行两遍delete操作,会发生什么呢?这可能是一场灾难,可能会破坏该堆及自由内存表。

那我们该如何避免呢?这里我们就需要使用深拷贝。

#include <iostream>
#include <string>
using namespace std; class aa
{
public:
aa()
{
cout << "调用构造函数" << endl;
f = new char[];
}
aa(aa const & s)
{
cout << "调用拷贝构造函数" << endl;
f = new char[];
strcpy(f, s.f);
}
~aa()
{
cout << "调用析构函数" << endl;
delete[] f;
}
char * f;
}; int main(int argc, char **argv)
{
aa p;
printf("p.f=%p\n", p.f);
strcpy(p.f, "Computer");
cout << p.f << endl;
aa q(p);// 调用用戶的拷贝构造函数
printf("q.f=%p\n", q.f);
cout << q.f << endl; strcpy(p.f, "Software");
cout << p.f << endl;
cout << q.f << endl; strcpy(q.f, "Software");
cout << p.f << endl;
cout << q.f << endl; return ;
}

运行结果:

调用构造函数
p.f=
Computer
调用拷贝构造函数
q.f=
Computer
Software
Computer
Software
Software
调用析构函数
调用析构函数

现在我们可以看到,p.f和q.f分别指向不同的内存区域。

来自:http://blog.csdn.net/sg131971/article/details/7045278

C++构造函数和拷贝构造函数详解的更多相关文章

  1. 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解

     c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...

  2. 【C++】拷贝构造函数(深拷贝,浅拷贝)详解

    一.什么是拷贝构造函数  首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对 ...

  3. C++ 构造函数、拷贝构造函数、赋值运算符

    <C++ Primer Plus> 12.1 动态内存和类 12.1.1 复习示例和静态类成员 不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存 如果在头文 ...

  4. c++ 构造函数,拷贝构造函数,析构函数与赋值操作符

    题目: 为下面的Rectangle类实现构造函数,拷贝构造函数,赋值操作符,析构函数. class Shape { int no; }; class Point { int x; int y; }; ...

  5. 类string的构造函数、拷贝构造函数和析构函数

    原文:http://www.cnblogs.com/Laokong-ServiceStation/archive/2011/04/19/2020402.html   类string的构造函数.拷贝构造 ...

  6. C++中的构造函数,拷贝构造函数和赋值运算

    关于C++中的构造函数,拷贝构造函数和赋值运算,以前看过一篇<高质量C++/C编程指南>的文章中介绍的很清楚,网上能搜索到,如果想详细了解这方面的知识可以参看一下这篇文章. 常见的给对象赋 ...

  7. 编写类String的构造函数、拷贝构造函数、析构函数和赋值函数

    一.题目: class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &othe ...

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

    类默认函数:构造函数,拷贝构造函数,赋值函数和析构函数 // person.h #ifndef _PERSON_H_ #define _PERSON_H_ class Person{ public : ...

  9. C++中构造函数,拷贝构造函数和赋值函数的区别和实现

    C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象 ...

随机推荐

  1. [深入浅出Cocoa]iOS程序性能优化

    本文转载至 http://blog.csdn.net/kesalin/article/details/8762032 [深入浅出Cocoa]iOS程序性能优化 罗朝辉 (http://blog.csd ...

  2. g++: command not found的解决

    G++没有装或却没有更新   以下方法都可以试试: centos: yum -y update gcc yum -y install gcc+ gcc-c++   ubuntu: apt-get up ...

  3. javaweb开发之EL表达式

    一.EL简介 EL全名为Expression Language,它主要用于替换JSP页面中的脚本表达式<%= %>,从各种类型的Web域中检索Java对象.获取数据.它可以很方便地访问Ja ...

  4. Detours3.0 文档翻译

    http://blog.csdn.net/buck84/article/details/8289991 拦截二进制函数 Detours库能够在执行过程中动态拦截函数调用.detours将目标函数前几个 ...

  5. 解决表单GET提交后台数据乱码问题

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/ForeverCjl/article/details/36180933     ​在页面上提交数据到s ...

  6. sam模板

    SAM模板 struct SAM{ * ; struct node{ node*nxt[],*fail; int len; }; node*root;int cnt; node no[maxn]; n ...

  7. linux CentOS7.2安装ffmpeg-3.0.2

    ffmpeg是一款视频处理软件,在php5.5前以php_ffmpeg.dll扩展的方式存在,通过网上查资料显示,从php5.5以后不支持该扩展了.那么在linux系统下安装ffmpeg.方法如下: ...

  8. maven项目所遇到的问题解决

    1.在Eclipse中创建Maven的Web项目时出现错误:An internal error occurred during: "Retrieving archetypes:". ...

  9. Linux各类压宿包的解压方法

    01-.tar格式解包:[*******]$ tar xvf FileName.tar 打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩 ...

  10. 基于Jquery的XML解析器,返回定制的HTML

    依据HTML模板返回解析的XML 依赖jQuery 1.4​1. [代码]基于Jquery的xml解析器并返回定制的HTML     /** *  jQuery插件 *  Author: pureco ...