`
897371388
  • 浏览: 526569 次
文章分类
社区版块
存档分类
最新评论

由Point p1 = p和p1 = p的区别想到的关于copy构造函数和赋值操作符重载函数的调用时机问题

 
阅读更多

今天在论坛上看到一个帖子:http://bbs.csdn.net/topics/390642928?page=1#post-396087799,涉及到一个copy构造函数和赋值操作符重载函数的调用时机问题,更正了我一直以来的一个对着俩函数的理解上的误区,这个错误相信很多人都会犯过,随后我问了周围几个人,果然不出所料!特此记录,以飨读者!

首先看这样一个简单的程序,涉及到copy构造函数和赋值操作符重载:

#include<iostream>

using namespace std;

class Point 
{ 
private: 
	int m_x,m_y; 
public: 
	Point() 
	{ 
		m_x = 0; 
		m_y = 0; 
	} 
	Point(int x, int y) 
	{ 
		m_x = x; 
		m_y = y; 
	} 
	Point(const Point& p)
	{
		m_x = p.m_x;
		m_y = p.m_y;
		cout<<"copy constructor is called!"<<endl;
	}
	Point& operator=(const Point& p)
	{
		m_x = p.m_x;
		m_y = p.m_y;
		cout<<"= operator is called!"<<endl;

		return *this;
	}
}; 

int main()
{
	Point p(1, 2);
	Point p1 = p;

	return 0;
}

在main函数中的Point p1 = p这条语句,程序的执行结果应该是调用哪个函数呢?看下运行结果:

令人惊讶的是,调用的是copy构造函数,并没有像预期的那样调用赋值操作符重载函数!

百思不得其解,将程序做了下改动:

#include<iostream>

using namespace std;

class Point 
{ 
private: 
	int m_x,m_y; 
public: 
	Point() 
	{ 
		m_x = 0; 
		m_y = 0; 
	} 
	Point(int x, int y) 
	{ 
		m_x = x; 
		m_y = y; 
	} 
	Point(const Point& p)
	{
		m_x = p.m_x;
		m_y = p.m_y;
		cout<<"copy constructor is called!"<<endl;
	}
	Point& operator=(const Point& p)
	{
		m_x = p.m_x;
		m_y = p.m_y;
		cout<<"= operator is called!"<<endl;

		return *this;
	}
}; 

int main()
{
	Point p(1, 2);
	Point p1;
	p1 = p;

	return 0;
}

将Point p1 = p;改成了Point p1; p1 = p;看下执行结果:


这次调用的确实赋值操作符的重载函数!非常奇怪!

在度娘的帮助下,终于找到了答案!其中的关键就是

Point p1 = p;

Point p1;

p1 = p;

的区别问题!

其实Point p1 = p与Point p1(p)是等价的,都表示“用实例p来初始化p1”,调用的当然是copy构造函数了,Point p1 = p千万不能理解成是把p赋值给p1,这是我一直以来犯下的一个错误!


Point p1;

p1 = p;

就表示先定义并初始化一个Point实例p1,然后将p赋值给p1,这当然会调用=operator了!到这里终于恍然大悟了!

总结了一下copy构造函数和赋值运算法重载函数的调用时机:

1、对象在创建时使用其他的对象初始化

Point p(q); //此时复制构造函数被用来创建实例p
Point p = q; //此时复制构造函数被用来在定义实例p时初始化p

2、对象作为函数的参数进行值传递时

func(p); //此时p作为函数的参数进行值传递,p入栈时会调用复制构造函数创建一个局部对象,与函数内的局部变量具有相同的作用域.


3、一个对象以值传递的方式从函数返回

Point func()

{

Point p;

return p;

}


需要注意的是,赋值并不会调用复制构造函数,赋值只是赋值运算符(重载)在起作用
p = q; //此时没有复制构造函数的调用!

简单来记的话就是,如果对象在声明的同时将另一个已存在的对象赋给它,就会调用复制构造函数;如果对象已经存在,然后将另一个已存在的对象赋给它,调用的就是赋值运算符(重载)
















分享到:
评论

相关推荐

    构建一个类Point,它提供两个公有的构造函数,一个没有参数的Point构造函数和一个有两个double参数的构造函数。

    构建一个类Point,它提供两个公有的构造函数,一个没有参数的Point构造函数和一个有两个double参数的构造函数。另外在该类中提供一个静态方法计算两个点的直线距离,传入参数为两个Point类实例。然后设计一个测试类...

    构造函数的继承问题 笔记

    子类如果有多个构造函数的时候,父类要么没有构造函数, 让编译器自动产生,那么在执行子类构造函数之前先执行编 译器自动产生的父类的缺省构造函数;要么至少要有一个显 式的缺省构造函数可以让子类的构造函数调用...

    详解C++中对构造函数和赋值运算符的复制和移动操作

    复制构造函数和复制赋值运算符 从 C++ 11 中开始,该语言支持两种类型的分配:复制赋值和移动赋值。 在本文中,“赋值”意味着复制赋值,除非有其他显式声明。 赋值操作和初始化操作都会导致对象被复制。 赋值:在将...

    C++操作符重载

    除了函数调用操作符之外,重载操作符的形参数目(包括成员函数的隐式this指针)与操作符的操作数数目相同。函数调用操作符可以接受任意数目的操作数。  大多数操作符都可以重载,所以我列出不能重载的操作符,...

    重载函数的运行

    对Point类重载“++”、“--”运算符,实现坐标值的改变。 #include using namespace std; class point { public: point(){}; point(int a,int b) { x=a; y=b; } point operator++(); point operator++(int)...

    CircleTest_java_设计一个circle_点类_圆类_

    设计Point类,包括构造函数和计算点之间距离的方法(考虑重载形式);设计Circle类中构造函数、计算面积的 getArea()方法、判断点是否在圆中的方法contains(Point p)和contains(int x int y)两种重载形式;设计测试...

    对point类重载++和--运算符

    对point类重载++和--运算符.................................................................................

    C++ 课程作业 多态性 运算符重载-综合(Point类)

    请定义一个Point类,将前置++和后置++运算符重载为成员函数,实现成员变量m_x和m_y的加一操作 同时重载流插入运算符,实现对Point类对象的格式化输出。例如 Point p; cout&lt;&lt;p; 输出结果为: (0,0) 请根据给定的...

    vc实验 实验八运算符重载

    1、 编写一个简单复数类Scomplex,要求用友元函数重载“+”、“-”运算符,用成员函数重载“=”运算符,使之能够实现整数或浮点数和复数的加法和减法,并且进行测试。 2、空间一点p的坐标为(x,y,z),其中x,y,z为...

    point类重载运算符

    1、 对Point类重载++和――运算符 编写C++程序完成以下功能: (1) Point类的属性包括点的坐标(x,y); (2) 实现 Point类重载++和――运算符:  ++p,--p,p++,p--。  ++和――分别表示x,y增加或...

    C++上机实验报告实验六.doc

    } Point Point::operator++(int) //重载前置++运算符为Point类成员函数 { Point old=*this; ++(this-&gt;_x); ++(this-&gt;_y); return old; } Point & Point::operator--() //重载后置--运算符为Point类成员函数 { _x--;...

    Point类重载运算符

    利用C++实现Point类重载运算符。利用C++实现Point类重载运算符。

    Kotlin学习教程之操作符重载详解

    在 Kotlin 中,我们可以用 约定的操作符,代替 调用代码中以特定的命名定义的函数,来实现 与之对应的操作。例如在类中定义了一个名为 plus 的特殊方法,就可以使用加法运算符 + 代替 plus() 的方法调用。由于你无法...

    实现一个三维坐标的Point类。

    1、 实现一个三维坐标的Point类。包含一个构造函数、一个拷贝构造函数、一个将点变为负值的函数negate()、一个返回该点到原点(0,0,0)距离的函数norm()和一个输出点坐标的函数print()。

    定义三个类Point,Circle和Cylinder,Point类为基类,为上述3个类添加计算面积的成员函数Area(),要求函数Area()采用虚函数的形式,并通过基类指针调用虚函数Area()。

    题目:定义三个类Point,Circle和Cylinder,Point类为基类,为上述3个类添加计算面积的成员函数Area(),要求函数Area()采用虚函数的形式,并通过基类指针调用虚函数Area()。 编程环境:vs2010 属性:控制台应用程序...

    对类Point重载(自增,自减)运算符

    对类Point重载“++”(自增)、“--”(自减)运算符,要求同时重载前缀和后缀。 使得下列主函数能够正确运行:

    C++实验5多态性(4学时)

    (1)定义Point类,有坐标_x,_y两个成员变量;对Point类重载“++”(自增)、“--”(自减)运算符,实现对坐标值的改变。 (2)定义一个车(vehicle)基类,有Run、Stop等...“=”运算符实现people类对象的赋值操作。

    NYIST-C++实验指导书实验5

    提示:该程序中point类的构造函数定义不正确, 在main()中对数据成员的访问不正确。要求修改程序后,在主函数中创建一个对象并初始化为坐标(5,5),然后输出这个点的X,Y坐标。 #include using namespace std; ...

    绘制贝赛尔样条,C#源代码Point[] p = {

    绘制贝赛尔样条,C#源代码Point[] p = { new Point(10, 100), // start point of first spline new Point(75, 10), // first control point of first spline new Point(80, 50), // ...

Global site tag (gtag.js) - Google Analytics