文档库 最新最全的文档下载
当前位置:文档库 › 类的构造函数、析构函数、复制构造函数和赋值操作符

类的构造函数、析构函数、复制构造函数和赋值操作符

类的构造函数、析构函数、复制构造函数和赋值操作符
类的构造函数、析构函数、复制构造函数和赋值操作符

类的构造函数、析构函数、复制构造函数和赋值操作符

作者:lyb661 时间:20140318

首先,回顾一下有关函数的知识。

函数声明一般由三个部分组成:返回类型、函数名和由圆括号括起来的参数表。

(1)函数可以没有返回类型,这时返回类型由void表示;

(2)函数名标志函数的接口,也是与其他函数区别的标志;

(3)函数可以没有参数,也可以有一至多个参数;

(4)可以根据参数类型、数量的差别重载函数。例如:

int sum(int a,int b);

void write(char c);

void display()const;

重载函数的例子:

void swap(int x,int y);

void swap(double x,double y);

上面是一些带有内置类型参数的函数的例子。类类型同样有与自己相关的函数。其中有几个特殊的成员函数,对类来说至为重要。

1、类的构造函数(consructor):构造函数用于创建类对象时完成必要的初始化工作。所有的类都需要构造函数。它没有返回类型,函数与类同名,可以没有,也可以有多个参数,如果必要。

//////////////////////////////////

//【例1】Data_class1

#include

using std::cout;

using std::endl;

class Data

{

int value;

public:

Data(int initial=0):value(initial){} //构造函数constructor

int read()const{return value;}

void write(int i){value=i;}

};

int main()

{

Data a(10);

cout<

Data b;

cout<

b.write(20);

cout<

return 0;

}

运行结果:

10

20

//////////////////////////////////

关于构造函数有以下几点:

(1)对于任何类,编译器会自动调用一个默认的构造函数;

(2)如果定义了自己的构造函数,则默认的构造函数将不再工作;

(3)同一般的函数一样,构造函数也可以被重载。

(4)可以定义默构造函数,如编译器合成的那样工作。

Data(int initial=0):value(initial){}就是一个重载的有默认值的构造函数。当创建对象a(10)时只有调用它才能正常工作。注意到该构造函数的参数有个默认值"0"。如果没胡这个0,则对象b就不能被建立。它代替默认构造函数的部分工作。

对于这个简单的Data类,它的默认构造函数应该是这样:Data(){}。这个由编译器合成的构造函数用于创建一个对象而不显式地初始化。如果用这个默认构造函数替换我们自己定义的构造函数,则a对象的建立是无效的,而对象b的成员初始值是无定义的,有兴趣的话可以自己试一试。当然,也可以用成员函数read()来完成一些初始化工作。

总之,像这样一个简单的类,默认构造函数的工作也不是尽如人意的。

对于复杂一点的类呢?

//////////////////////////////////

//【例2】Data_class2(警告:本程序有内存泄漏风险不要上机运行)

#include

using std::cout;

using std::endl;

class Data

{

int *ip;

public:

Data(int &i):ip(new int(i)){}

~Data(){delete ip;} //destructor

int read()const{return *ip;}

void write(int n){*ip=n;}

};

int main()

{

int obj=10;

Data a(obj);

cout<

Data b=a;

cout<

return 0;

}

//////////////////////////////////

本例是上一例的改进,由于类具有指针成员,并且申请自由存储,所以重新定义了析构函数的行为,用于删除指针。

2、类的析构函数(destructor) :析构函数与类同名,在名字前加符号~以与构造函数相区别。

析构函数用于在类对象超出作用域时按类中声明次序的逆序撤销各个成员。与构造函数有所不同:尽管类定义了自己的析构函数,编译器合成的析构函数也会正常工作。由于函数重载规则的限制,析构函数是不能被重载的。为什么?我们所谓自定义的意思,不过在它常规工作量外给它加了点的担子。

对于上面的Data类来说,它的默认的析构函数~Data(){}的工作并不能令人满意。该类有一个int类型的指针成员,在程序运行过程中由该指针申请了自由存储,所以必须定义一个析构函数,在程序结束后删除指针,进而撤销自由存储。这个工作默认的析构函数是不能胜任的。

本程序潜在的风险当然还不只这些。当对象b建立的时候,b从a复制了指针成员。由于只是复制指针的值,这两个指针共享一个int变量。因为析构对象与创建对象的顺序相反,后建立的对象首先被析构(“后进先出”last int first out)。当析构函数将b的指针删除,然后这个int变量也将撤销,致使a的指针不再指向任何对象,而成了悬垂指针。而当这个指针被删除时,同一块内存撤销了两次,内存泄漏的风险就在这里。

一般将上述复制行为称为浅复制,而规避风险的办法就是定义一个复制构造函数来完成深层复制。

//////////////////////////////////

//【例3】Data_class3

#include

using std::cout;

using std::endl;

class Data

{

int *ip;

public:

Data(int &i):ip(new int(i)){}

~Data(){delete ip;}

Data(const Data&);

int read()const{return *ip;}

void write(int n){*ip=n;}

};

Data::Data(const Data &dt)

{

ip=new int(*dt.ip);

}

int main()

{

int obj=10;

Data a(obj);

cout<

Data b=a;

cout<

b.write(20);

cout<<"a:"<

return 0;

}

运行结果:

10

10

a:10,b:20

//////////////////////////////////

3、类的复制构造函数(copy constructor)

从上边运行结果,a与b的指针成员不同,指向的变量也不同,复制后各归各家,不再纠缠不清。

Data::Data(const Data &dt);就是所谓的复制构造函数。它也与类同名,参数是同类的常引用。与默认构造函数一样,复制构造函数可由编译器隐式调用。

也就是说第例2的程序中,编译器合成了复制构造函数,只是不能有效工作罢了。

与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数。合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。这说明了复制构造函数也不能重载的。不过,我们可以通过编写代码,来规定构造函数的行为,令其有效地工作。

例2中的复制构造函数之所以不能有效地工作,是因为它是浅复制,只复制指针的值,而不涉及指针指向的对象。

有另外的办法来规避内存泄漏的风险,就是对类的指针成员进行引用计数,当指针的引用计数多于1时绝不删除指针,只当引用计数为1,也就是最后一个指针时才删除指针,这就是所谓智能指针。这略复杂些,稍后再讨论。

上边例3实际还有风险存在。

//////////////////////////////////

//【例4】Data_class4

#include

using std::cout;

using std::endl;

class Data

{

int *ip;

public:

Data(int i=0):ip(new int(i)){}//constructor

//Data(){} //default constructor

~Data(){delete ip;} //destructor

Data(const Data&);//copy constructor

Data &operator=(const Data&); //assignment operator

int read()const{return *ip;}

void write(int n){*ip=n;}

};

Data::Data(const Data &dt)

{

ip=new int(*dt.ip);

}

Data &Data::operator=(const Data &dt)

{

if(this!=&dt)

*ip=*dt.ip;

return *this;

}

int main()

{

int obj=10;

Data a(obj);

cout<

Data b=a;

cout<

b.write(20);

Data c;

c=b;// uses assignment operator

c.write(30);

cout<<"a:"<

return 0;

}

运行结果

10

10

a:10,b:20,c:30

//////////////////////////////////

例4又增加一个赋值操作符。因为类Data中有赋值工作:c=b。如果像常规那样进行赋值,内存泄漏的风险依然存在。

4、类的赋值操作符(assignment operator) :赋值操作符是类成员函数重载操作符的一个的例子。它使应用于一般内置变量的赋值操作符"="一样应用于类对象。就是说,我们可以将一个类对象赋给另一个同类的对象,而它们成员之间的赋值行为将由我们编写的代码来规定。

与复制构造函数一样,如果类没有定义自己的赋值操作符,则编译器会合成一个。类也可以定义自己的赋值操作符。一般而言,如果类需要复制构造函数,它也会需要赋值操作符,同时也需要析构函数。

本例中,默认的赋值操作符不能正常工作,默认的赋值操作符,只复制了指针的值,还属于浅复制。赋值符两边对象的指针纠缠在一起。

Data &Data::operator=(const Data &dt)

{

ip=dt.ip;

return *this;

只有重新定义赋值操作符,才能进行深复制。

Data &Data::operator=(const Data &dt)

{

if(this!=&dt)

*ip=*dt.ip;

return *this;

}

1、首先用条件语句if(this!=&dt)检验左右操作数是否相同,避免自我赋值;

2、然后通过语句*ip=*dt.ip;完成深复制;

3、最后返回调用对象。

我们的复制控制技术,属于《C++Primer》所谓的值语义:值型副本是独立的:对副本的改变不会影响原有对象。

如果使用计数与共享对象一起存储。需要创建一个单独类指向共享对象并管理使用计数。使用辅助类来管理指针,即智能指针技术。这项技术本身并不复杂,由于篇幅所限,将在以后讨论。

最后,我们用另一段代码来验证本文所阐述的技术,做为结尾。

//////////////////////////////////

//【例5】Data_class5

#include

using std::cout;

using std::endl;

class Data

{

int *ip;

static int count;

public:

Data(int *i):ip(new int(*i)){++count;}//constructor

Data():ip(NULL){++count;} //default constructor

~Data(){cout<

Data(const Data&);//copy constructor

Data &operator=(const Data&); //assignment operator

int read()const{return *ip;}

void write(int n){*ip=n;}

};

int Data::count=0;

Data::Data(const Data &dt)

ip=new int(*dt.ip);

++count;

}

Data &Data::operator=(const Data &dt)

{

if(this==&dt)

return *this;

delete ip;

ip=new int(*dt.ip);

return *this;

}

int main()

{

int obj=10;

Data a(&obj);

cout<

Data b=a;

cout<

b.write(20);

Data c;

c=b;// uses assignment operator

c.write(30);

cout<<"a:"<

<

return 0;

}

这里添加了一点新内容:

1、用空指针为指针成员类增加一个默认构造函数;以便能创建一个未初始化的类对象,并且在后面编写赋值操作时,可以删除它的指针。因为删除空指针是安全的。

2、在析构函数里输出引用计数来验证它是否正常工作,这与共享对象指针管理中的引用计数无关;

3、赋值操作符的代码也与上例不同。这样更好理解:先验证左右操作数是否相同;然后,删除左操作数,并将右操作数赋给它;最后,返回调用对象自身。本质上和以前没多少区别。

//////////////////////////////////

C默认构造函数的作用

C#默认构造函数的作用 本文详细介绍C#默认构造函数的作用 构造函数主要用来初始化对象。它又分为静态(static)和实例(instance)构造函数两种类别。大家应该都了解如果来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性。实际上,我说错了。正确的说法是:以及在类中保留空参数构造函数的重要性。我们来写一个类A,代码如下: view plaincopy to clipboardprint? public class A { public int Number; //数字 public string Word; //文本 } //在Test类中实例化 public class Test { static void Main() { A a = new A(); //实例化,A()即为类A的默认构造函数 Console.WriteLine(“Number = {0}"nWord = {1}”,a.Number,a.Word); Console.read(); } } 输出的结果是: Number = 0 Word = ******************************* using System; class Point { public int x, y,z; public Point() { x = 0; y = 0; z = 0; } public Point(int x, int y,int z) { //把函数内容补充完整 this.x = x; this.y =y;

this.z =z; } public override string ToString() { return(String.Format("({0},{1},{2})", x, y,z)); } } class MainClass { static void Main() { Point p1 = new Point(); Point p2 = new Point(10,20,30); Console.WriteLine("三维中各点坐标:"); Console.WriteLine("点1的坐标为{0}", p1); Console.WriteLine("点2的坐标为{0}", p2); } } ******************************************************************************* ********* C#类的继承,构造函数实现及其调用顺序 类层层派生,在实例化的时候构造函数的调用顺序是怎样的? --从顶层基类开始向子类方向顺序调用无参构造. 默认构造(无参构造)和带参构造什么时候调用?--默认将从顶层父类的默认构造一直调用到当前类的默认构造. 下面是示例: /**//*--===------------------------------------------===--- 作者:许明会 日期:类的派生和构造函数间的关系,调用层次及实现 日期:2008年1月18日 17:30:43 若希望类能够有派生类,必须为其实现默认构造函数. 若类没有实现带参构造,编译器将自动创建默认构造函数. 若类实现了带参构造,则编译器不会自动生成默认构造. --===------------------------------------------===---*/ using System; namespace xumh { public class MyClass { public MyClass () {

C++拷贝构造函数(复制构造函数)

有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将Word 文档拷贝到U盘去复印店打印,将D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。 严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化: ?分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。 ?初始化就是首次对内存赋值,让它的数据有意义。注意是首次赋值,再次赋值不叫初始化。初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。说白了,初始化就是调用构造函数。 很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。

那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。 1.#include 2.#include https://www.wendangku.net/doc/1912625238.html,ing namespace std; 4. 5.void func(string str){ 6.cout<

定义构造函数的四种方法

定义类的构造函数 作者:lyb661 时间:20150613 定义类的构造函数有如下几种方法: 1、使用默认构造函数(类不另行定义构造函数):能够创建一个类对象,但不能初始化类的各个成员。 2、显式定义带有参数的构造函数:在类方法中定义,使用多个参数初始化类的各个数据成员。 3、定义有默认值的构造函数:构造函数原型中为类的各个成员提供默认值。 4、使用构造函数初始化列表:这个构造函数初始化成员的方式显得更紧凑。 例如:有一个学生类。其中存储了学生的姓名、学号和分数。 class Student { private: std::string name; long number; double scores; public: Student(){}//1:default constructor Student(const std::string& na,long nu,double sc); Student(const std:;string& na="",long nu=0,double sc=0.0); Student(const std:;string& na="none",long nu=0,double sc=0.0):name(na),number(nu),scores(sc){} ……….. void display() const; //void set(std::string na,long nu,double sc); }; ......... Student::Student(const std::string& na,long nu,double sc) { name=na; number=nu; scores=sc; } void Student::display()const { std::cout<<"Name: "<

(完整版)拷贝构造函数

拷贝构造函数 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 #include using namespace std; class CExample { private: int a; public: //构造函数 CExample(int b) { a = b;} //一般函数 void Show () { cout< using namespace std;

private: int a; public: //构造函数 CExample(int b) { a = b;} //拷贝构造函数 CExample(const CExample& C) { a = C.a; } //一般函数 void Show () { cout<

为什么要引入构造函数和析构函数汇总

1.为什么要引入构造函数和析构函数? 对象的初始化是指对象数据成员的初始化,在使用对象前,一定要初始化。由于数据成员一般为私有的(private),所以不能直接赋值。对对象初始化有以下两种方法:类中提供一个普通成员函数来初始化,但是会造成使用上的不便(使用对象前必须显式调用该函数)和不安全(未调用初始化函数就使用对象)。 当定义对象时,编译程序自动调用构造函数。 析构函数的功能是当对象被撤消时,释放该对象占用的内存空间。析构函数的作用与构造函数正好相反,一般情况下,析构函数执行构造函数的逆操作。在对象消亡时,系统将自动调用析构函数,执行一些在对象撤消前必须执行的清理任务。 2. 类的公有、私有和保护成员之间的区别是什么? ①私有成员private: 私有成员是在类中被隐藏的部分,它往往是用来描述该类对象属性的一些数据成员,私有成员只能由本类的成员函数或某些特殊说明的函数(如第4章讲到的友员函数)访问,而类的外部根本就无法访问,实现了访问权限的有效控制,使数据得到有效的保护,有利于数据的隐藏,使内部数据不能被任意的访问和修改,也不会对该类以外的其余部分造成影响,使模块之间的相互作用被降低到最小。private成员若处于类声明中的第一部分,可省略关键字private。 ②公有成员public:公有成员对外是完全开放的,公有成员一般是成员函数,它提供了外部程序与类的接口功能,用户通过公有成员访问该类对象中的数据。 ③保护成员protected: 只能由该类的成员函数,友元,公有派生类成员函数访问的成员。保护成员与私有成员在一般情况下含义相同,它们的区别体现在类的继承中对产生的新类的影响不同,具体内容将在第5章中介绍。缺省访问控制(未指定private、protected、public访问权限)时,系统认为是私有private 成员。 3. 什么是拷贝构造函数,它何时被调用?

拷贝构造函数

实验7拷贝构造函数 一、实验目的 (1) 掌握类的声明和对象的声明。 (2) 掌握拷贝构造函数的定义与使用 (3) 了解拷贝构造函数调用的时机 二、实验内容及步骤 1 新建c++源文件,找到week14文件夹中的copyStruDefine.cpp文件,复制到新建的源文件中运行,将运行结果记录下来,分析程序中执行哪条语句引起拷贝构造函数被调用的,将该语句的行号记录下来。 分析程序,第46 条语句Point pa(1,2) 执行时会调用构造函数,第47 条语句 Point pb=pa 执行时会调用拷贝构造函数。 2 程序中添加一个distance函数,用来计算2个点之间的距离。代码如下:

运行程序,记录运行结果。 分析程序,第52,53 条语句Point pa(7,4); Point pb(1,2); 执行时会调用构造函数,第46,47 条语句 double dx=a1.getX()-a2.getX();double dy=a1.getY()-a2.getY(); 执行时会调用拷贝构造函数。 3 设计一个函数mirror用来返回一个点在x轴的镜像坐标,如点A坐标为(1,2),它的镜像点A’坐标为(1,-2)。

分析:函数的结构分成2部分,函数头部和函数体 (1)函数的函数头部分语法格式:返回类型函数名(参数) 可以确定的是函数名mirror;这个函数会计算出一个点的镜像并返回,点的镜像还是一个点,因此可以确定函数的返回类型是void ;这个函数会将某个点的镜像计算出来,那到底计算的是那个点的镜像呢?这是不确定的,将不确定的因素定义为函数的参数,因此函数的参数类型是Point ;现将函数的第一行补充完整。 返回类型mirror(参数) (2)分析函数的函数体部分,即用”{ }”包围的部分。 我们通过参数传递接收到一个点的坐标,现在要计算另一个点的坐标(镜像点),因此需要在函数体内定义另外一个点类型的对象来存放镜像点的坐标。将镜像点的x坐标赋值为参数点的x坐标值,将镜像点的y坐标赋值为参数点的y坐标值的负数值(需要注意Point类中的x和y成员都是私有的)。将镜像点坐标赋值完成后,用return语句将镜像点返回。 (3)在主函数中测试mirror函数。 #include #include using namespace std; /* 类的函数成员-->构造函数(创建对象并赋初值) int a=10; int b=a;//创建变量b并赋初值,这个初值放在a中 创建对象(新)时,构造函数的参数是对象(已存在) --拷贝构造函数 */ class Point{ private: double x;

构造函数

c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初学者有所帮助。 c++类的构造函数详解 一、构造函数是干什么的 class Counter { public: // 类Counter的构造函数 // 特点:以类名作为函数名,无返回类型 Counter() { m_value = 0; } private: // 数据成员 int m_value; } 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作 eg: Counter c1; 编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象c1的m_value值设置为0 故: 构造函数的作用:初始化对象的数据成员。 二、构造函数的种类 class Complex { private : double m_real; double m_imag;

public: // 无参数构造函数 // 如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做 // 只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来 Complex(void) { m_real = 0.0; m_imag = 0.0; } // 一般构造函数(也称重载构造函数) // 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理) // 例如:你还可以写一个Complex( int num)的构造函数出来 // 创建对象时根据传入的参数不同调用不同的构造函数 Complex(double real, double imag) { m_real = real; m_imag = imag; } // 复制构造函数(也称为拷贝构造函数) // 复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中// 若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询有关“浅拷贝”、“深拷贝”的文章论述 Complex(const Complex & c) { // 将对象c中的数据成员值复制过来 m_real = c.m_real; m_img = c.m_img; } // 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象 // 例如:下面将根据一个double类型的对象创建了一个Complex对象 Complex::Complex(double r) { m_real = r; m_imag = 0.0;

【重要】C++拷贝函数详解 20150111

C++拷贝函数详解 1.什么是拷贝构造函数: CA(const CA& C)就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构 造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参 数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷 贝构造函数就会被自动调用。 也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数: ①程序中需要新建立一个对象,并用另一个同类的对象对它初始化,如前面介绍的那样。 ②当函数的参数为类的对象时。 在调用函数时需要将实参对象完整地传递给形参,也就是需要建立一个实参的拷贝,这就 是按实参复制一个形参,系统是通过调用复制构造函数来实现的,这样能保证形参具有和实参 完全相同的值。 ③函数的返回值是类的对象。 在函数调用完毕将返回值带回函数调用处时。 此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。如 Box f( ) //函数f的类型为Box类类型 {Box box1(12,15,18); return box1; //返回值是Box类的对象 } int main( ) {Box box2; //定义Box类的对象box2 box2=f( ); //调用f函数,返回Box类的临时对象,并将它赋值给 box2 } 如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的 拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。 自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。 浅拷贝和深拷贝 在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的

C++实验三 构造函数和析构函数题目+答案

实验三构造函数和析构函数 班级:B135A2 学号: 201322688 姓名:杨弘成绩: 一.实验目的 1.理解构造函数和析构函数作用; 2.掌握各种类型的构造函数和析构函数的使用; 3.掌握构造函数和析构函数的调用顺序。 二.使用的设备和仪器 计算机+Windows XP +Visual C++6.0 三.实验内容及要求 1.阅读程序,写出运行结果,然后上机运行,将机器运行结果与人工运行的结果进行比较,并对每一行输出做出分析。 (1) #include using namespace std; class MyClass { public: MyClass(); MyClass(int xx); MyClass(int xx,int yy); MyClass(MyClass &); void Display(); void Set(int, int); ~ MyClass(); private: int x,y; }; MyClass:: MyClass() { cout<<"执行无参构造函数:" ; x=0;y=0; cout<<"x="<

cout<<"执行一个参数构造函数:" ; x=xx;y=0; cout<<"x="<

实验三 构造函数和析构函数

实验三、构造函数和析构函数 一、实验目的 1.掌握声明类的方法,类和类的成员的概念以及定义对象的方法。 2.初步掌握用类和对象编制基于对象的程序。 3.学习检查和调试基于对象的程序。 4.掌握类的构造函数和析构函数的概念和使用方法。 5.掌握对象数组、对象的指针及其使用方法。 二、实验内容 1.检查下面的程序,找出其中的错误,并改正之。然后上机调试,使之能正常运行。(1) #include using namespace std; class A {public: void A(int i=0){m=i;} void show(){cout< using namespace std; class X { private: int a=0; int &b; const int c; void setA(int i){a=i;} X(int i){ a=i;} public:

int X(){ a=b=0;} X(int i, int j, int k){ a=i; b=j; c=k; } setC(int k) const { c=c+k;} }; int main() { X x1; X x2(2) ; X x3(1,2,3) ; x1.setA(3) ; return 0 ; } 2.请先阅读下面的程序,写出程序运行的结果,然后再上机运行程序,验证自己分析的结果是否正确。 (1) #include using namespace std; class test{ public: test(); int getint( ){return num;} float getfloat( ){return fl;} ~test( ); private: int num; float fl; }; test::test( ) { cout << "Initalizing default" << endl; num=0;fl=0.0; } test::~test( ) { cout << "Destructor is active" << endl; } int main( ) { test array[2]; cout << array[1].getint( )<< " " << array[1].getfloat( ) <

C++考试题(选择题)

1、选择题 1、___A__只能访问静态成员变量。 A 静态函数 B 虚函数 C 构造函数 D 析构函数 2、下列的各类函数中,__C___不是类的成员函数。 A 构造函数 B 析构函数C友元函数 D 拷贝构造函数 3、友元的作用_A__。 A 提高程序的运行效率 B 加强类的封装性 C 实现数据的隐藏性 D 增加成员函数的种类 4、类模板的使用实际上是将类模板实例化成一个具体的_D____。 A 类 B 对象 C 函数 D 模板类 5、下列函数中,___C__不能重载。 A 成员函数 B 非成员函数 C 析构函数 D 构造函数 6、___C__是一个在基类中说明的虚函数,它在该基类中没有定义,但要求任何派生类都必须定义自己的版本。 A 虚析构函数B虚构造函数C纯虚函数 D 静态成员函数 7、__A___是istream的派生类,处理文件输入;___C__是iostream的派生类,可以同时处理文件的I/O。 A、ifstream B、ostream C、fstream D、ofstream 8、对于派生类的构造函数,在定义对象时构造函数的执行顺序为: 先执行__A___,再执行__B___,后执行__C___。 A 成员对象的构造函数 B 基类的构造函数 C 派生类本身的构造函数 9、局部变量可以隐藏全局变量,那么在有同名全局变量和局部变量的情形时,可以用__A___提供对全局变量的访问。 A 域运算符 B 类运算符 C 重载 D 引用 10、一个__C___允许用户为类定义一种模式,使得类中的某些数据成员及某些成员函数的返回值能取任意类型。 A 函数模板 B 模板函数 C 类模板 D 模板类 11、系统在调用重载函数时,往往根据一些条件确定哪个重载函数被调用,在下列选项中,不能作为依据的是___D__。 A 参数个数 B 参数的类型 C 函数名称D函数的类型 12、如果一个类至少有一个纯虚函数,那么就称该类为__A___。 A 抽象类 B 虚基类 C 派生类 D 以上都不对 13、进行文件操作时需要包含__B___文件。 A iostream B fstream C stdio.h D stdliB、h 14、在C++中,打开一个文件,就是将这个文件与一个__B___建立关联;关闭一

Java默认构造函数的作用

class Person { private String name=""; private int age=0; public Person() { System.out.println("person无参数构造函数"); } public Person(String name,int age) { https://www.wendangku.net/doc/1912625238.html,=name; this.age=age; System.out.println("person 2 参数的构造函数"); } } class Student extends Person { private String school; private String grade; public Student() { System.out.println("student 无参数的构造函数"); } public Student(String name ,int age,String school) { System.out.println("student 3 参数的构造函数"); } public Student(String name ,int age,String school,String grade) { super(name,age); this.school=school;

this.grade=grade; System.out.println("student 4 参数的构造函数,super()."); } } class Test { public static void main(String [] args) { System.out.println("st1:"); Student st2=new Student(); System.out.println("---------------------------"); System.out.println("st2:"); Student st=new Student("zhangshan",76,"武大"); System.out.println("---------------------------"); System.out.println("st3:"); Student st3=new Student("lisi",24,"武大","研究生"); } } /* ======================================= 输出如下: E:JavaWork>java Test st1: person无参数构造函数 student 无参数的构造函数 --------------------------- st2: person无参数构造函数 student 3 参数的构造函数 --------------------------- st3:

C++拷贝构造函数的几个细节

C++拷贝构造函数的几个细节 关键字: c++ 拷贝构造函数是C++最基础的概念之一,大家自认为对拷贝构造函数了解么?请大家先回答一下三个问题: 1.以下函数哪个是拷贝构造函数,为什么? 1.X::X(const X&); 2.X::X(X); 3.X::X(X&, int a=1); 4.X::X(X&, int a=1, b=2); 2.一个类中可以存在多于一个的拷贝构造函数吗? 3.写出以下程序段的输出结果, 并说明为什么?如果你都能回答无误的话,那么你已经对拷贝构造函数有了相当的了解。 1.#include 2.#include 3. 4.struct X { 5. template 6. X( T& ) { std::cout << "This is ctor." << std::endl; } 7. 8. template 9. X& operator=( T& ) { std::cout << "This is ctor." << std:: endl; } 10.}; 11. 12.void main() { 13. X a(5); 14. X b(10.5); 15. X c = a; 16. c = b; 17.} 解答如下: 1. 对于一个类X,如果一个构造函数的第一个参数是下列之一: a) X&

b) const X& c) volatile X& d) const volatile X& 且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数. 1.X::X(const X&); //是拷贝构造函数 2.X::X(X&, int=1); //是拷贝构造函数 2.类中可以存在超过一个拷贝构造函数, 1.class X { 2.public: 3. X(const X&); 4. X(X&); // OK 5.}; 注意,如果一个类中只存在一个参数为X&的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化. 1.class X { 2.public: 3. X(); 4. X(X&); 5.}; 6. 7.const X cx; 8.X x = cx; // error 如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝 构造函数. 这个默认的参数可能为X::X(const X&)或X::X(X&),由编译器根据上下文决定选择哪一个. 默认拷贝构造函数的行为如下: 默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造. 拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作. a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数. b)如果数据成员是一个数组,对数组的每一个执行按位拷贝. c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符 对其进行赋值. 3. 拷贝构造函数不能由成员函数模版生成.

C拷贝构造函数的几个知识点总结及示例代码

C++拷贝构造函数的知识点总结 一拷贝构造函数是C++最基础的概念之一,大家自认为对拷贝构造函数了解么?请大家先回答一下三个问题: 1.以下函数哪个是拷贝构造函数,为什么? 1.X::X(const X&); 2.X::X(X); 3.X::X(X&, int a=1); 4.X::X(X&, int a=1, b=2); 2.一个类中可以存在多于一个的拷贝构造函数吗? 3.写出以下程序段的输出结果, 并说明为什么?如果你都能回答无误的话,那么你已经对拷贝构造函数有了相当的了解。 1.#include 2.#include 3. 4.struct X { 5. template 6. X( T& ) { std::cout << "This is ctor." << std::endl; } 7. 8. template 9. X& operator=( T& ) { std::cout << "This is ctor." << std::endl; } 10.}; 11. 12.void main() { 13. X a(5); 14. X b(10.5); 15. X c = a; 16. c = b; 17.} 解答如下: 1.对于一个类X,如果一个构造函数的第一个参数是下列之一: a) X& b) const X& c) volatile X&

d) const volatile X& 且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数. 1.X::X(const X&); //是拷贝构造函数 2.X::X(X&, int=1); //是拷贝构造函数 2.类中可以存在超过一个拷贝构造函数, 1.class X { 2.public: 3. X(const X&); 4. X(X&); // OK 5.}; 注意,如果一个类中只存在一个参数为X&的拷贝构造函数,那么就不能使用const X或volatile X的对象实行拷贝初始化. 1.class X { 2.public: 3. X(); 4. X(X&); 5.}; 6. 7.const X c x; 8.X x = c x; // error 如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数. 这个默认的参数可能为X::X(const X&)或X::X(X&),由编译器根据上下文决定选择哪一个. 默认拷贝构造函数的行为如下: 默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造. 拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作. a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数. b)如果数据成员是一个数组,对数组的每一个执行按位拷贝. c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值. 3.拷贝构造函数不能由成员函数模版生成. 1.struct X { 2.template 3. X( const T& ); // NOT copy ctor, T can't be X 4. 5.template 6. operator=( const T& ); // NOT copy ass't, T can't be X 7.};

相关文档
相关文档 最新文档