C++拷贝构造函数详解

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

https://www.360docs.net/doc/a413585283.html,/blog/static/11 22252200691732259479/

拷贝构造函数问题集锦

2006-10-18 16:48:10| 分类:C/C++ | 标签:c/c++ 体验 it linux |字号订阅

一、什么是拷贝构造函数

用一个类的一个对象去构造另一个对象,或者说初始化一个新构造的对象时。往往会通过拷贝构造函数。假设存在一个类A,那么声明A的拷贝构造函数如下:

A (A &a);

可见,它与一般的构造函数在于,他的参数是本类对象的一个引用。

二、什么情况会调用构造函数

从构造函数的定义来看,当用一个对象去初始化或构造一个对象时,就会调用构造函数。在程序的运行过程中,这个初始化或构造的过程可能是隐式的,也可能是显式的。显式的只有一种情况,如下面调用(假想存在对象obj)

A(obj);

另外还有一些隐式调用的情况。为了说明方便,我们首先写如下类。

#include

#include

using namespace std;

class CopyTest

{

public:

int i;

CopyTest()

{

cout << "调用默认构造函数!" <

i = 3;

}

//COPY构造函数

CopyTest( CopyTest &obj)

{

cout << "调用拷贝构造函数!"<

i = 10;

}

CopyTest operator = (CopyTest &obj)

{

cout <<"调用赋指重载!"<

this->i = obj.i;

}

};

类中有一个默认构造函数的重载,COPY构造函数的重载,和一个赋值运算符的重载,我们通过几个调用来说明何时会调用COPY构造函数。

1.定义对象-- 调用指定的构造函数

int main(int argc, char *argv[])

{

CopyTest obj1;

getchar();

return EXIT_SUCCESS;

}

在上例中,调用默认的构造函数。如果在定义对象的同时写上其它的参数。运行过程中会调用相应的参数。

2、初始化一个对象

初始化指定义一个对象同时给他同值。如下面这种写法

CopyTest obj2 = obj1;

但是,如果把上述语句改为

CopyTest obj2 ;

obj2= obj1;

运行时并没有调用COPY构造函数。原因是,上述过程只是赋值,而不是一个初始化的过程。事实上,系统默认已经对obj2进行了初始化。

3、形参实体化

看下面一个例子:

int Test(CopyTest obj)

{

return 1;

}

int main(int argc, char *argv[])

{

CopyTest obj1;

Test(obj1);

getchar();

return EXIT_SUCCESS;

}

在这个过程中调用的拷贝构造函数。我们可以把这个过程理解为CopyTest obj = obj1;显然这是一个初始化的过程。所以,理所当然的调用的拷贝构造函数。

值得指出的是,当传递的参数是引用或指针时,不会调用该类的构造函数。原因是,这个过程,只是对引用和指针的复制。而不是对对角本身的复制,没有产生新的对象,形参和实参所指代的是一个对象。当然这个过程不会调用拷贝构造函数了。

4、返回一个对象

当某个函数,以一个对象作为返回值时,会调用拷贝构造函数。事实上,当函数返回时,会创建一个临时变量,并对其进行初始化,把所要返回的对象赋给临时变量。所以这个过程是要调用拷贝构造函数的。

三、何时重载拷贝构造函数

C++规定,每一个类都有一个默认的无参构造函数和一个默认的拷贝构造函数。一般情况下,我们运用这两个默认的构造函数就可以完成上述的工作。但有一些情况是例外。

例如:类体内的成员是需要开辟动态开辟堆内存的,如果我们不自定义拷贝构造函数而让系统自己处理,那么就会导致堆内存的所属权产生混乱,试想一下,已经开辟的一端堆地址原来是属于对象a的,由于复制过程发生,b对象取得是a已经开辟的堆地址,一旦程序产生析构,释放堆的时候,计算机是不可能清楚这段地址是真正属于谁的,当连续发生两次析构的时候就出现了运行错误。

上例是一个很明显的深拷贝问题。所谓深拷贝与浅拷贝可以如下理解:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源的情况视为浅拷贝。(摘自太平洋电脑网)

往往在深拷贝中,我们要重载拷贝构造函数。如下:

#include

#include

using namespace std;

class CopyTest

{

public:

char *buf;

CopyTest()

{

cout << "调用默认构造函数!" <

//i = 3;

buf = (char*)malloc(50);

}

//COPY构造函数

CopyTest( CopyTest &obj)

{

cout << "调用拷贝构造函数!"<

i = 10;

buf = (char*)malloc(50);

strcpy(buf,obj.buf);

}

~CopyTest()

{

cout << "调用析构函数";

free((void*)buf);

}

CopyTest operator = (CopyTest &obj)

{

cout <<"调用赋指重载!"<

if (buf != NULL)

{

strcpy(buf,obj.buf);

}

}

};

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

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

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

(完整版)拷贝构造函数

拷贝构造函数 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: 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++拷贝函数详解 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 } 如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的 拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。 自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。 浅拷贝和深拷贝 在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的

所学知识点总结

设计者往往对使用者抱有很多期望,希望使用者遵循一些共同的约束,但是期望总是很难得到满足的,从基础的设计原则上来说,我们不应该对设计者抱有太多的期望,宁愿予以更多的使用约束,即只有固定的路线可走。 如果你觉得某项语法规定不合理,那么请自行模拟它的种种特性,你会发现它是有道理的,只不过有时它可能会产生很多危害性,但是不应该忽略其有益的方面。 1.四种C++风格的类型转换 a. static_cast: 纯粹的内容转换,可能会造成实际内容的损失; b. dynamic_cast: 只对有虚类型有用,因为虚表的存在才有RTTI; c. const_cast: 去const化; d. reinterpret_cast: 让编译器以该转换所注明的类型去看待内存段所表示的类型,一般是针对指针类型,一般来说是不怎么安全的,而且对于函数指针的转换有时是不可移植的,因为不同编译器可能有不同的函数指针表示法(命令方法和存储方法的不同?); 2.数据类型转换: a. double=int/int;//做法是错误的,右侧不会提升至double再进行运算的,类型提升的原则是如果不大于整型则会提升至int,但有更大类型则会继续提升,正确写法是: double=int/(double)int;或者double=(double)int/(double)int; b. int=usigned char;//错误,正确做法:usigned char->usignedint->int 3.new operator和operator new: 前者是个操作符名称,后者则代表某个函数。 new operator:new操作符仅仅是我们常见的new的名称,它实际代表两段操作:operator new (这是一个我们可以自行重载的函数,作用是分配内存,并返回所分配内存的首地址,换句话说,即使有意进行偏离或者像malloc一样设置一定字节进行特殊用途都是可以的)和调用构造函数。记住编译器看见new操作符时意味着它会先调用new操作函数(operator new()),然后调用构造函数。 上图说明了定位new和定位delete为何是类型对应的关系。

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___建立关联;关闭一

拷贝构造函数&默认拷贝构造函数&拷贝构造函数调用几种情况

一、拷贝构造函数 如果类中没有说明拷贝构造函数,则系统自动生成一个缺省复制构造函数,作为该类的公有成员 也可以进行自定义拷贝构造函数 自定义拷贝构造函数的例子: Test::Test(const Test& other) : num_(other.num_) { //num_ = other.num_; cout<<"Initializing with other "<

构造函数

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++拷贝构造函数的几个细节

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.};

C++期末考试复习重点、易错知识点整理

C++重点、易错知识点整理 第一章 1、泛型程序设计是指向程序中数据类型中加入类型参数的一种能力,也称为参数化的类型 或参数多态性。 2、c++程序开发通常要经过5个阶段,包括编辑、预处理、编译、连接、运行与调试。 3、编译过程分为词法分析、语法分析、代码生成这3个步骤。 4、使用名字空间std的方法有3种: 1、利用using namespace使用名字空间;使用方法如下: 2、用域分辨符::为对象分别指定名字空间;例如: 3、用using与域分辨符指定名字空间;例如: 5、c++中常用操作符: 第二章 1、c++的数据类型:

2、在定义变量的同时赋初值还有另外一种方法,就是在变量后面将初值放在括号中,格式 如下: 3、常变量定意格式: 或 ※在定义常变量时,一定要赋初值,且在程序中间不能更新其值。 4、常量和非左值表达式是没有内存地址的。 5、在逻辑表达式求值中注意短路求值。 6、运算符优先级的规律: (1)运算符的优先级按单目、双目、三目、赋值依次降低; (2)算术、移位、关系、按位、逻辑运算的优先级依次降低。 7、标准c++提供了新式的强制类型转换运算,格式如下: ※static_cast用于一般表达式的类型转换; ※reinterpret_cast用于非标准的指针数据类型转换,如将void*转换成char*; ※const_cast将const表达式转换成非常量类型,常用于将限制const成员函数的const 定义解除; ※dynamic_cast用于进行对象指针的类型转换。 第三章 第四章 1、内联函数的定义必须出现在对该函数的调用之前。 2、递归函数不能定义为内联函数。 3、说明一个内联函数只是请求而不是命令编译器对它进行扩展。 带有默认形参值的函数: 1、若函数具有多个形参,则默认形参值必须自右向左连续的定义,并且在一个默认形参值 的右边不能有未指定默认值的参数。 2、在调用一个函数时,若果省去了某个实参,则直到最右端的实参都要省去。 3、默认形参值的说明必须出现在函数调用之前。若函数原型中已给出了形参的默认值,则 在函数定义中不得重复制定,即使所指定的默认值完全相同也不行。 4、在同一个作用域内,一旦定义了默认形参值,就不能在定义它。 5、如果几个函数说明出现在不同的作用域内,则允许对它们提供不同的默认形参值。 6、在函数的原型给出了形参的默认值时,形参名可以省略。 第五章 1、相同类型的指针类型才可以想减;两个指针是不可以相加的。 2、一个void类型的地址赋值给非void类型的指针变量,要使用类型强制转换。 3、要初始化多重指针,要从第一层开始,逐步向高层进行。

C++类的构造函数和复制构造函数

C++类的构造函数和复制构造函数 [日期:2011-03-11] 来源:LinuxLinux 作者:pcliuguangtao 首先,我们先看一个小小的问题: #include #include using namespace std; class C{ public: C(){ cout<<"cccc"<

那么怎样才叫显式的调用那? 比如已经有一个Student类 class Student { public: Student(int num,int score ): m_number( num ),m_score(score ){} Studnet( ){} //默认构造函数 void PrintInfo( ) { cout<

C++小程序练习

C++小程序练习 1 函数重载 定义重载函数max3用于计算三个数的最大值(参数类型分别为int和double)。 2 类的组合 定义point类,数据成员包括x,y,成员函数包括构造函数,拷贝构造函数和析构函数,以及setx,getx,sety,gety四个属性函数。定义line类,端点由两个point类的对象组成,包括构造函数,析构函数以及计算线段长度的函数getlength。在main函数中,定义line 的对象,并输出其长度。 3 对象数组和函数 定义student类,数据成员包括姓名name和成绩score,成员函数包括构造函数,拷贝构造函数和析构函数。定义函数void highestscore(student s[]),输出分数最高的学生姓名和分数。在main函数中定义student s[N],调用highestscore函数,输出分数最高的学生姓名和分数。 4 静态数据成员 设计一个书类,能够保存书名、定价,所有书的本数和总价。(将书名和定价设计为普通数据成员;将书的本数和总价设计为静态数据成员) 5 动态内存分配 定义point类,数据成员包括x,y,成员函数包括构造函数,拷贝构造函数和析构函数,以及setx,getx,sety,gety四个属性函数。在main函数中,用new和delete分配和释放N个point的数组。(N是const常量,N=10) 6 类的继承 定义一个point类,包含私有数据成员x,y,成员函数包括无参构造函数,带参构造函数,set和get属性函数。定义circle类,从point类公有派生,增加数据成员半径r,成员函数包括无参构造函数,带参构造函数,计算面积函数getarea。在main函数中定义一个circle 的对象,并计算其面积。 7 虚基类 定义vehicle类,数据成员包括私有的weight,公有的构造函数,析构函数和输出函数dispaly;从vehicle类公有派生car类,增加数据成员载人数personnum,公有的构造函数,析构函数和输出display;从vehicle类公有派生truck类,增加数据成员载货量laod,公有的构造函数,析构函数和输出函数display;从car类和truck类共同公有派生出pickup 类,包括公有的构造函数和输出函数。在main函数中,定义pickup类对象,并输出其基本信息。 8 运算符重载,友元函数和this指针 定义一个计数器类counter,具备自增,自减功能(前后缀);输入输出>>,<<功能。在main 函数里测试该类。 9 虚函数和抽象类 定义一个抽象类shape,包括公有的计算面积area函数,计算体积volume函数,输出基本信息函数printinfo(三个函数均为纯虚函数)。从shape公有派生point类,增加私有数据成员x,y坐标,以及构造函数,析构函数。从point公有派生circle类,增加私有数据成员半径r,以及构造函数,析构函数。从circle公有派生cylinder类,增加私有数据成员高度h,以及构造函数,析构函数。(在定义三个派生类的过程中,自己考虑需要重定义哪个虚函数)。在main函数中,定义shape类的指针,指向派生类的对象,输出三类对象

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. 拷贝构造函数不能由成员函数模版生成. 1.struct X { 2. template 3. X( const T& ); // NOT copy ctor, T can't be X 4.

拷贝构造函数的几点细节

拷贝构造函数的标准写法如下: class Base { public: Base(){} Base(const Base &b){..} // } 上述写法见得最多,甚至你认为理所当然。 那么如果我们不写成引用传递呢,而是值传递,那么会怎样? class Base { public: Base(){} Base(const Base b){} // } 编译出错:error C2652: 'Base' : illegal copy constructor: first parameter must not be a 'Base' 事实上,你可以从这个小小的问题认真搞清楚2件事: 1) 拷贝构造函数的作用就是用来复制对象的,在使用这个对象的实例来初始化这个对象的一个新的实例。其实,个人认为不应该叫这些constructor(default constructor, copy constructor....)为构造函数,更佳的名字应该是"初始化函数"(见我的另一片文章). 2) 参数传递过程到底发生了什么? 将地址传递和值传递统一起来,归根结底还是传递的是"值"(地址也是值,只不过通过它可以找到另一个值)! i)值传递: 对于内置数据类型的传递时,直接赋值拷贝给形参(注意形参是函数内局部变量); 对于类类型的传递时,需要首先调用该类的拷贝构造函数来初始化形参(局部对象);如void foo(class_type obj_local){}, 如果调用foo(obj); 首先class_type obj_local(obj) ,这样就定义了局部变量obj_local供函数内部使用 ii)引用传递: 无论对内置类型还是类类型,传递引用或指针最终都是传递的地址值!而地址总是指针类型(属于简单类型), 显然参数传递时,按简单类型的赋值拷贝,而不会有拷贝构造函数的调用(对于类类型). 上述1) 2)回答了为什么拷贝构造函数使用值传递会产生无限递归调用... 3). 如果不显式声明拷贝构造函数的时候,编译器也会生成一个默认的拷贝构造函数,而且在一般的情况下运行的也很好。但是在遇到类有指针数据成员时就出现问题了:因为默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)指向了相同的

相关文档
最新文档