📄 copyconstructorandassign.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>复制建构函式、物件的指定</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">C++
Gossip: 复制建构函式、物件的指定</a></h1>
当您宣告一个物件时,您可以使用另一个物件将之初始化,例如:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SomeClass s1;</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SomeClass s2 = s1;</span><br>
</div>
<br>
这么作的话,s1的属性会一一的“复制”至s2的每一个属性,下面这个程式是个简单的示范,您进行物件的指定,而最后用&运算子取出物件的记忆体
位址,您可以看到两个物件所占的位址并不相同: <br>
<br>
<pre>#include <iostream><br>using namespace std;<br><br>class Employee { <br>public: <br> Employee() {<br> _num = 0; <br> _years = 0.0;<br> } <br> <br> Employee(int num, double years) { <br> _num = num; <br> _years = years; <br> }<br> <br> int num() {<br> return _num;<br> }<br> <br> double years() {<br> return _years;<br> }<br> <br>private:<br> int _num;<br> double _years; <br>}; <br><br>int main() {<br> Employee p1(101, 3.5); <br> Employee p2 = p1; <br><br> cout << "p1 addr:\t" << &p1 << endl;<br> cout << "p1.num: \t" << p1.num() << endl;<br> cout << "p1.years:\t" << p1.years() << endl;<br> <br> cout << "p2 addr:\t" << &p2 << endl; <br> cout << "p2.num: \t" << p2.num() << endl;<br> cout << "p2.years:\t" << p2.years() << endl;<br> <br> return 0;<br>}</pre>
<span class="postbody"><br>
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">p1
addr: 0x22ff60<br>
p1.num: 101<br>
p1.years: 3.5<br>
p2 addr: 0x22ff50<br>
p2.num: 101<br>
p2.years: 3.5</span></small><span style="color: rgb(255, 255, 255);"><br>
</span></td>
</tr>
</tbody>
</table>
<br>
然而这中间潜藏着一个危机,尤其是在属性成员包括指标时,以 <a href="ConstructorDestructor.html">建构函式、
解构函式</a> 中的SafeArray类别来说,看看下面的程式问题会出在哪边: <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SafeArray arr1(10);</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SafeArray arr2 =
arr1;</span><br>
</div>
<br>
表面上看起来没有问题,但记得_array是int型态指标,而在解构函式是这么写的:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SafeArray::~SafeArray()
{</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">
delete [] _array;</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">}</span><br>
</div>
<br>
arr2复制了arr1的属性,当然也包括了_array指标,如果arr1资源先被回收了,但arr2的_array仍然参考至一个已被回收资源的位
址,这时再存取该位址的资料就有危险,例如下面这段程式就可能造成程式不可预期的结果:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SafeArray *arr1 = new
SafeArray(10);</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">SafeArray arr2 =
*arr1;</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">delete arr1;</span><br>
</div>
<br>
为了避免这样的错误,您可以定义一个复制建构函式,当初始化时如果有提供复制建构函式,则会使用您所定义的复制建构函式,您可以在定义复制建构函式时,当
遇到指标成员时,产生一个新的资源并指定位址给该成员,例如:<br>
<ul>
<li>SafeArray.h</li>
</ul>
<pre>class SafeArray { <br>public: <br> int length; <br><br> // 复制建构函式 <br> SafeArray(const SafeArray&);<br> // 建构函式 <br> SafeArray(int); <br> // 解构函式 <br> ~SafeArray();<br> <br> int get(int); <br> void set(int, int); <br><br>private:<br> int *_array; <br><br> bool isSafe(int i); <br>};</pre>
<span class="postbody">
</span><br>
<ul>
<li>SafeArray.cpp</li>
</ul>
<pre>#include "SafeArray.h"<br><br>// 复制建构函式 <br>SafeArray::SafeArray(const SafeArray &safeArray) <br> : length(safeArray.length) {<br> _array = new int[safeArray.length];<br> <br> for(int i = 0; i < safeArray.length; i++) {<br> _array[i] = safeArray._array[i];<br> }<br>}<br><br>// 动态配置阵列<br>SafeArray::SafeArray(int len) {<br> length = len;<br> _array = new int[length];<br>}<br><br>// 测试是否超出阵列长度<br>bool SafeArray::isSafe(int i) {<br> if(i > length || i < 0) {<br> return false;<br> } <br> else {<br> return true;<br> }<br>}<br><br>// 取得阵列元素值<br>int SafeArray::get(int i) {<br> if(isSafe(i)) {<br> return _array[i];<br> }<br> <br> return 0;<br>}<br><br>// 设定阵列元素值<br>void SafeArray::set(int i, int value) {<br> if(isSafe(i)) {<br> _array[i] = value;<br> }<br>}<br><br>// 删除动态配置的资源<br>SafeArray::~SafeArray() {<br> delete [] _array;<br>}</pre>
<span class="postbody">
</span><br>
如果属性成员中有指标型态,除了为物件始化撰写复制建构函式之外,最好再重载=指定运算子,因为=指定运算子预设也是将物件的属性值一一复制过去,您应该
重载=指定运算子,在遇到指标成员时,产生位址上的资源复本,例如:<br>
<ul>
<li>SafeArray.h</li>
</ul>
<pre>class SafeArray { <br>public: <br> int length; <br> <br> // 复制建构函式 <br> SafeArray(const SafeArray&);<br> // 建构函式 <br> SafeArray(int); <br> // 解构函式 <br> ~SafeArray();<br> <br> int get(int); <br> void set(int, int);<br> <br> // 重载=运算子 <br> SafeArray& operator=(const SafeArray&);<br><br>private:<br> int *_array; <br><br> bool isSafe(int i); <br>};<br></pre>
<span class="postbody">
</span><br>
<ul>
<li>SafeArray.cpp</li>
</ul>
<pre>#include "SafeArray.h"<br><br>// 复制建构函式 <br>SafeArray::SafeArray(const SafeArray &safeArray) <br> : length(safeArray.length) {<br> _array = new int[safeArray.length];<br> <br> for(int i = 0; i < safeArray.length; i++) {<br> _array[i] = safeArray._array[i];<br> }<br>}<br><br>// 重载=指定运算子 <br>SafeArray& SafeArray::operator=(const SafeArray &safeArray) {<br> if(this != &safeArray) {<br> length = safeArray.length;<br><br> // 先清除原有的资源 <br> delete [] _array;<br> <br> _array = new int[safeArray.length];<br> for(int i = 0; i < safeArray.length; i++) {<br> _array[i] = safeArray._array[i];<br> } <br> }<br> <br> return *this;<br>}<br><br>// 动态配置阵列<br>SafeArray::SafeArray(int len) {<br> length = len;<br> _array = new int[length];<br>}<br><br>// 测试是否超出阵列长度<br>bool SafeArray::isSafe(int i) {<br> if(i > length || i < 0) {<br> return false;<br> } <br> else {<br> return true;<br> }<br>}<br><br>// 取得阵列元素值<br>int SafeArray::get(int i) {<br> if(isSafe(i)) {<br> return _array[i];<br> }<br> <br> return 0;<br>}<br><br>// 设定阵列元素值<br>void SafeArray::set(int i, int value) {<br> if(isSafe(i)) {<br> _array[i] = value;<br> }<br>}<br><br>// 删除动态配置的资源<br>SafeArray::~SafeArray() {<br> delete [] _array;<br>}<br></pre>
<br>
<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -