C++:对象的赋值和复制
3.6.1 对象赋值语句
如同基本类型赋值语句一样,同类型的对象之间也可以进行赋值,即一个对象的值可以赋给
另一个对象。这里所指的对象的赋值是指对其中的数据成员赋值,而不对成员函数赋值。
例如:A和B是同一类的两个对象,那么下述对象赋值语句
B=A;
就能把对象A的数据成员的值逐位复制给对象B
//例3.24 对象赋值语句示例
#include<iostream>
using namespace std;
class Myclass{
public:
void set(int i,int j)
{
a = i;
b = j;
}
void show()
{
cout<<a<<" "<<b<<endl;
}
private:
int a,b;
};
int main()
{
Myclass o1,o2;
o1.set(,);
o2 = o1; //将对象o1的值赋给对象o2
o1.show();
o2.show();
return ;
}
/*
该程序中,语句:
o2 = o1;
等价于语句:
o2.a = o1.a;
o2.b = o1.b;
因此,运行此程序将显示:
20 5
20 5
说明:
1、在使用对象赋值语句进行对象赋值时,两个对象的类型必须相同,如对象的类型不同,
编译时将出错。
2、两个对象之间的赋值,仅仅使这些对象中数据成员相同,而两个对象仍是分离的。例如
本例对象后,再调用o1.set()设置o1的值,不会影响o2的值。
3、对象赋值是通过默认赋值运算符函数实现的
4、将一个对象的值赋给另一个对象时,多数情况下都是成功的,但当类中存在指针时,可能
会产生错误。
*/
3.6.2 拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用。拷贝构造函数的作用
是,在建立一个新对象时,使用一个已经存在的对象去初始化这个新对象。
例如: Point p2(p1);
其作用是:在建立新对象p2时,用已经存在的对象p1去初始化对象p2,在这个过程中就要
调用拷贝构造函数。
拷贝构造函数具有以下特点:
(1)因为该函数也是一种构造函数,所以其函数名与类名相同,并且该函数也没有返回值
类型。
(2)该函数只有一个参数,并且是同类对象的引用
(3)每一个类都必须有一个拷贝构造函数。程序员可以自定义拷贝构造函数,用于按照需要
初始化新对象。如果程序员没有定义类的拷贝构造函数,系统就会自动生成产生一个默认的拷贝
构造函数,用于复制出数据成员值完全相同的新对象。
1. 自定义拷贝构造函数
一般格式: 类名::类名(const 类名 &对象名)
{
//拷贝构造函数的函数体
}
下面是一个用户自定义的拷贝构造函数:
class Point{
public:
Point(int a,int b) //构造函数
{
x = a;
y = b;
}
Point(const Point &p) //拷贝构造函数
{
x = 2*p.x;
y = 2*p.y;
}
.....
private:
int x;
int y;
};
假如p1为类Point的一个对象,则下述语句可以在建立新对象p2时调用拷贝构造函数初始化p2;
Point p2(p1);
//例3.25 自定义拷贝构造函数的使用。
#include<iostream>
using namespace std;
class Point{
public:
Point(int a,int b) //普通构造函数
{
x = a;
y = b;
}
Point::Point(const Point &p) //自定义的拷贝构造函数
{
x = *p.x;
y = *p.y;
}
void print()
{
cout<<x<<" "<<y<<endl;
}
private:
int x;
int y;
};
int main()
{
Point p1(,); //定义对象p1,调用了普通的构造函数
Point p2(p1); //调用拷贝构造函数,用对象p1初始化对象p2
p1.print();
p2.print();
return ;
}
/* 本例中定义对象p2时,调用了自定义拷贝构造函数。程序运行结果如下:
30 40
60 80 调用拷贝构造函数的一般形式为:
类名 对象2(对象1); 上面的这种拷贝构造函数的方法称为“代入法”。除了用代入法调用拷贝构造函数外,
还可以采用"赋值法"调用拷贝构造函数,与基本类型的变量初始化类似.这种调用方的一般格式为:
类名 对象2=对象1;
当然,这种方法可以在一个语句中进行多个对象的复制。如
Point p2=p1,p3=p1; 如将例3.25主函数main改为如下形式:
int main()
{
Point p1(10,20);
Point p2=p1; //以赋值法调用拷贝构造函数
p1.print();
p2.print();
return 0;
}
2. 默认的拷贝构造函数(程序员没有定义,系统会自动生成)
// 例3.26 默认的拷贝构造函数
#include<iostream>
using namespace std;
class Point{
public:
Point(int a,int b) //普通的构造函数
{
x = a;
y = b;
} // Point::Point(const Point &p)//不用写,系统会默认存在(需要用时直接调用)
// {
// x = p.x;
// y = p.y;
// } void print()
{
cout<<x<<" "<<y<<endl;
}
private:
int x;
int y;
};
int main()
{
Point p1(,); //调用普通构造函数
Point p2(p1); //用代入法调用默认的拷贝构造函数,用对象p1初始化对象p2
Point p3=p1; //用赋值法调用默认的拷贝构造函数,用对象p1初始化对象p3
p1.print();
p2.print();
p3.print();
return ;
} /*
调用拷贝构造函数的方法有两种:代入法、赋值法 代入法:Point p2(p1) 赋值法:Point p2=p1 */
3.调用拷贝构造函数的三种情况
(1)当用类的一个对象去初始化另一个对象时,拷贝构造函数将会被调用,
如例3.26主函数中的下属语句
Point p2(p1); //用代入法调用默认的拷贝构造函数,用对象p1初始化对象p2
Point p3=p1; //用赋值法调用默认的拷贝构造函数,用对象p1初始化对象p3
(2)当函数的形参是类的对象,在调用函数进行形参和实参结合时,拷贝构造函数将会被调用
例如:
void fun1(Point p) //形参是类Point的对象p
{
p.print();
}
int main()
{
point p1(10,20);
fun1(p1); //调用函数fun1时,实参p1是类Point的对象
//将调用拷贝构造函数,初始化形参对象p
return 0;
}
理解:在main函数内,执行语句“fun1(p1)”,便是这种情况。在调用这个函数时,对象p1是实参
用它来初始化被调用函数的形参p时,需要调用拷贝构造函数。这时,如果类Point中有自定义
的拷贝构造函数时,就调用拷贝的构造函数,否则就调用系统自动生成的默认拷贝构造函数
(3)当函数的 返回值是类的对象,在函数调用完毕将返回值(对象)带回调用处时。此时将会
调用拷贝构造函数,将此对象赋值给一个临时对象并传到该函数的调用处。
例如: Point fun2() //函数fun2()的返回值类型是Point类类型
{
Point p1(10,30); //定义类Point的对象p1
return p1; // 函数的返回值是Point类的对象
}
int main()
{
Point p2; //定义类Point的对象p1
p2=fun2(); //函数执行完成,返回调用者时,调用拷贝构造函数(赋值法)
return 0;
}
理解:
由于对象p1是函数fun2中定义的,在调用函数fun2结束时,p1的生命周期结束了,因此在
函数fun2结束之前,执行语句"return p1"时,将会调用拷贝构造函数将p1的值复制到一个
临时对象中,这个临时对象是系统在主程序中临时创建的。函数运行结束时,p1对象消失,
但是临时对象将会通过语句"p2=fun2()"将它的值赋给对象p2,执行完这个语句后,临时对
象变自动消失了。
//例3.27 演示调用拷贝构造函数的3中情况 #include<iostream>
using namespace std;
class Point{
public:
Point(int a=,int b=); //声明构造函数
Point::Point(const Point &p); //声明拷贝构造函数
void print()
{
cout<<x<<" "<<y<<endl;
}
private:
int x,y;
};
Point::Point(int a,int b) //定义构造函数
{
x = a;
y = b;
cout<<"Using normal constructor\n";
}
Point::Point(const Point &p)//定义拷贝构造函数
{
x = * p.x;
y = * p.y;
cout<<"Using copy constructor\n";
}
void fun1(Point p) //形参是类Point的对象p
{
p.print();
}
Point fun2() //函数fun2()的返回值类型是Point类类型
{
Point p4(,); //定义类Point的对象p4
return p4; // 函数的返回值是Point类的对象
}
int main()
{
Point p1(,);//定义对象p1时,第1次调用普通的构造函数
p1.print(); Point p2(p1); //用带入法,用对象p1为对象p2进行初始化。此时会第1次调用拷贝构造函数
p2.print(); Point p3=p1; //用赋值法,用对象p1为对象p3进行初始化。此时会第2次调用拷贝构造函数
p3.print(); fun1(p1); //在调用fun1函数,实参和形参结合时, 此时会第3次调用拷贝构造函数 p2=fun2(); //在调用fun2函数,在函数内部第2次调用普通构造函数。而且,当调用fun2函数结束时,
//还是用赋值法,用返回的对象p4为对象p2进行赋值,会第4次调用拷贝构造函数
p2.print(); return ;
} 运行结果:
Using normal constructor Using Cpy constructor Using Cpy constructor Using Cpy constructor Using normal constructor
Using Cpy constructor 当没有自定义的拷贝构造函数时的运行结果:
Using normal constructor Using normal constructor
//再举一个实例为:
#include<iostream>
using namespace std;
class Point{
public:
Point(int a,int b)
{
x = a;
y = b;
}
/* Point::*/Point(const Point &p) //拷贝构造函数(用初始化过的对象为没有初始化过的对象进行初始化)
{
x = * p.x;
y = * p.y;
}
Point& operator = (const Point &p)//赋值运算符重载函数(用初始化过的对象为初始化过的对象进行赋值)
{
x = p.x;
y = p.y;
}
Point fun();
void print()
{
cout<<x<<" "<<y<<endl;
}
private:
int x,y;
};
Point::Point fun(Point p4)
{
return p4;
}
int main()
{
Point p1(,);
Point p3(,); p3=p1;//调用赋值运算符重载函数
p3.print(); Point p2 = fun(p1);//调用fun函数时,实参和形参结合,会第1次调用拷贝构造函数;调用fun函数结束时,
p2.print() ; // 返回的对象p4为未初始化的p2进行初始化,会第2次调用拷贝构造函数
}
C++:对象的赋值和复制的更多相关文章
- 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板
[源码下载] 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板 作者:webabcd 介绍不可或缺 Window ...
- C++中的对象的赋值和复制
对象的赋值 如果对一个类定义了两个或多个对象,则这些同类的对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象.这里所指的对象的值是指对象中所有数据成员的值. 对象之间的赋值也是通过赋值 ...
- C++ 对象的赋值和复制 基本的
对象的赋值 如果对一个类定义了两个或多个对象,则这些对象之间是可以进行赋值,或者说,一个对象的值可以赋值给另一个同类的对象.这里所指的值是指对象中所有数 据的成员的值.对象之间进行赋值是“ ...
- C++,对象的 =赋值 以及 复制构造函数赋值
1. C++默认实现了 = 号赋值:operator=只要将一个对象的内容的内容逐位复制给另外一个对象即可. 2. C++默认实现了复制构造函数:同样,只要将一个对象的内容的内容逐位复制给另外一个对象 ...
- effective c++:对象的赋值运算
operator 中处理”自我赋值“ operator=操作符缺省情况下返回引用——TYPE& TYPE::operator=(const TYPE&),原因很简单,operator= ...
- Python把同一个对象循环赋值给另外一个变量
Python把同一个对象循环赋值给另外一个变量,修改一个对象,其他对象也修改了 >>> row=['_'] * 3 >>> board = [] >>& ...
- python 对象/变量&赋值的几点思考
python 对象/变量 对象 Every object has an identity, a type and a value. An object's identity never changes ...
- java数组对象的浅层复制与深层复制
实际上,java中数组对象的浅层复制只是复制了对象的引用(参考),而深层复制的才是对象所代表的值.
- xml 转换成对象(采用反射机制对对对象属性赋值)
/// <summary> /// 采用反射机制对对对象属性赋值 /// </summary> /// <param name="node">& ...
随机推荐
- nginx服务器绑定域名和设置根目录
首先进入nginx安装目录的配置目录conf,然后执行 vi conf/nginx.conf 打开nginx的配置文件,找到并修改红字部分 server { listen default_server ...
- java基础之java基本数据类型
1.Java数据类型基本概念: 数据类型在计算机语言里面,是对内存位置的一个抽象表达方式,可以理解为针对内存的一种抽象的表达方式.接触每种语言的时候,都会存在数据类型的认识,有复杂的.简单的,各种数据 ...
- 【python】 开始第一个项目
根据这篇文章开始上手 http://www.oschina.net/translate/the-flask-mega-tutorial-part-i-hello-world 再加点东西 如果你的环境是 ...
- matlab实现共轭梯度法、多元牛顿法、broyden方法
共轭梯度法: function [ x, r, k ] = CorGrant( x0, A, b ) x = x0; r = b - A * x0; d = r; X = ones(length(x) ...
- Configuring My Site in SharePoint 2010
Configuring the User Profile Service in SharePoint 2010 http://sharepointgeorge.com/2010/configuring ...
- 包装设计模式的实现以改进BufferedReader中的readLine方法为例
实现与目标对象相同的接口 BufferedReader 定义一个变量记住目标对象 定义一个构造器接收被增强对象 覆盖需要增强的方法 对于不想增强的方法,直接调用目标对象的方法. package ...
- Team Homework #1 学长“学霸英语学习软件”试用
简介: 一款英语单词记忆和管理辅助软件. 基本功能: 内置GRE词汇及其常考形态.Webster英语解释 单词发音功能 单词测验模式 简易词典功能 基本界面 词库单词读取 单词测试 优点: 1.界面简 ...
- HTML弹出窗口
1.最简单的 <script type="text/javascript"> <!-- window.open("http://cn.bing.com& ...
- C# 越来越复杂了
自从三年前来到现在的公司以后,基本上不怎么使用.NET进行开发了.但最近因为公司有个CRM的项目,所以只有重新检起.NET进行开发. 因为近3年没有搞.NET的开发了,因此也不敢乱整个框架,在看了一周 ...
- sqlserver 获取时间年月日时分秒
转自:http://blog.itpub.net/14766526/viewspace-1156100/ select GETDATE() as '当前日期',DateName(year,GetDat ...