⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copyconstructorandassign.html

📁 关于 C++ 的历史无须我来介绍了
💻 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:&nbsp;复制建构函式、物件的指定</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的每一个属性,下面这个程式是个简单的示范,您进行物件的指定,而最后用&amp;运算子取出物件的记忆体
位址,您可以看到两个物件所占的位址并不相同: <br>

<br>

<pre>#include &lt;iostream&gt;<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 &lt;&lt; "p1 addr:\t" &lt;&lt; &amp;p1 &lt;&lt; endl;<br>    cout &lt;&lt; "p1.num: \t" &lt;&lt; p1.num() &lt;&lt; endl;<br>    cout &lt;&lt; "p1.years:\t" &lt;&lt; p1.years() &lt;&lt; endl;<br>        <br>    cout &lt;&lt; "p2 addr:\t" &lt;&lt; &amp;p2 &lt;&lt; endl;    <br>    cout &lt;&lt; "p2.num: \t" &lt;&lt; p2.num() &lt;&lt; endl;<br>    cout &lt;&lt; "p2.years:\t" &lt;&lt; p2.years() &lt;&lt; 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:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x22ff60<br>

p1.num:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 101<br>

p1.years:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.5<br>

p2 addr:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x22ff50<br>

p2.num:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 101<br>

p2.years:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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;">&nbsp;&nbsp;&nbsp;
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&amp;);<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 &amp;safeArray) <br>              : length(safeArray.length) {<br>    _array = new int[safeArray.length];<br>    <br>    for(int i = 0; i &lt; 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 &gt; length || i &lt; 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&amp;);<br>    // 建构函式     <br>    SafeArray(int); <br>    // 解构函式 <br>    ~SafeArray();<br>    <br>    int get(int); <br>    void set(int, int);<br>    <br>    // 重载=运算子 <br>    SafeArray&amp; operator=(const SafeArray&amp;);<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 &amp;safeArray) <br>              : length(safeArray.length) {<br>    _array = new int[safeArray.length];<br>    <br>    for(int i = 0; i &lt; safeArray.length; i++) {<br>        _array[i] = safeArray._array[i];<br>    }<br>}<br><br>// 重载=指定运算子 <br>SafeArray&amp; SafeArray::operator=(const SafeArray &amp;safeArray) {<br>    if(this != &amp;safeArray) {<br>        length = safeArray.length;<br><br>        // 先清除原有的资源         <br>        delete [] _array;<br>        <br>        _array = new int[safeArray.length];<br>        for(int i = 0; i &lt; 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 &gt; length || i &lt; 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 + -