zoukankan      html  css  js  c++  java
  • 第36课 经典问题解析三

    关于赋值的疑问?

    示例程序:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 class Test
     7 {
     8     int* m_pointer;
     9 public:
    10     Test()
    11     {
    12         m_pointer = NULL;
    13     }
    14     Test(int i)
    15     {
    16         m_pointer = new int(i);
    17     }
    18     Test(const Test& obj)
    19     {
    20         m_pointer = new int(*obj.m_pointer);
    21     }
    22     Test& operator = (const Test& obj)
    23     {
    24         if( this != &obj )
    25         {
    26             delete m_pointer;
    27             m_pointer = new int(*obj.m_pointer);
    28         }
    29         
    30         return *this;
    31     }
    32     void print()
    33     {
    34         cout << "m_pointer = " << hex << m_pointer << endl;
    35     }
    36     ~Test()
    37     {
    38         delete m_pointer;
    39     }
    40 };
    41 
    42 int main()
    43 {
    44     Test t1 = 1;
    45     Test t2;
    46     
    47     t2 = t1;
    48     
    49     t1.print();
    50     t2.print();
    51     
    52     return 0;
    53 }

    第22行是赋值操作符重载,返回值应该为引用类型,参数也应该为引用类型,否则容易出bug。

    24行的判断为了避免自赋值。因为在C语言中,i = i这种自赋值是合法的,C++为了兼容C语言,t2 = t2这种自赋值也是合法的。

    我们的数组类将拷贝构造定义为私有的,就是不允许拷贝构造,但是赋值操作应该是要允许的。

    改造程序:

     1 #ifndef _INTARRAY_H_
     2 #define _INTARRAY_H_
     3 
     4 class IntArray
     5 {
     6 private:
     7     int m_length;
     8     int* m_pointer;
     9     
    10     IntArray(int len);
    11     IntArray(const IntArray& obj);
    12     bool construct();
    13 public:
    14     static IntArray* NewInstance(int length); 
    15     int length();
    16     bool get(int index, int& value);
    17     bool set(int index ,int value);
    18     int& operator [] (int index);
    19     IntArray& operator = (const IntArray& obj);
    20     IntArray& self();
    21     ~IntArray();
    22 };
    23 
    24 #endif
      1 #include "IntArray.h"
      2 
      3 IntArray::IntArray(int len)
      4 {
      5     m_length = len;
      6 }
      7 
      8 bool IntArray::construct()
      9 {
     10     bool ret = true;
     11     
     12     m_pointer = new int[m_length];
     13     
     14     if( m_pointer )
     15     {
     16         for(int i=0; i<m_length; i++)
     17         {
     18             m_pointer[i] = 0;
     19         }
     20     }
     21     else
     22     {
     23         ret = false;
     24     }
     25     
     26     return ret;
     27 }
     28 
     29 IntArray* IntArray::NewInstance(int length) 
     30 {
     31     IntArray* ret = new IntArray(length);
     32     
     33     if( !(ret && ret->construct()) ) 
     34     {
     35         delete ret;
     36         ret = 0;
     37     }
     38         
     39     return ret;
     40 }
     41 
     42 int IntArray::length()
     43 {
     44     return m_length;
     45 }
     46 
     47 bool IntArray::get(int index, int& value)
     48 {
     49     bool ret = (0 <= index) && (index < length());
     50     
     51     if( ret )
     52     {
     53         value = m_pointer[index];
     54     }
     55     
     56     return ret;
     57 }
     58 
     59 bool IntArray::set(int index, int value)
     60 {
     61     bool ret = (0 <= index) && (index < length());
     62     
     63     if( ret )
     64     {
     65         m_pointer[index] = value;
     66     }
     67     
     68     return ret;
     69 }
     70 
     71 int& IntArray::operator [] (int index)
     72 {
     73     return m_pointer[index];
     74 }
     75 
     76 IntArray& IntArray::operator = (const IntArray& obj)
     77 {
     78     if( this != &obj )
     79     {
     80         int* pointer = new int[obj.m_length];
     81         
     82         if( pointer )
     83         {
     84             for(int i=0; i<obj.m_length; i++)
     85             {
     86                 pointer[i] = obj.m_pointer[i];
     87             }
     88             
     89             m_length = obj.m_length;
     90             delete[] m_pointer;
     91             m_pointer = pointer;
     92         }
     93     }
     94     
     95     return *this;
     96 }
     97 
     98 IntArray& IntArray::self()
     99 {
    100     return *this;
    101 }
    102 
    103 IntArray::~IntArray()
    104 {
    105     delete[]m_pointer;
    106 }
     1 #include <iostream>
     2 #include <string>
     3 #include "IntArray.h"
     4 
     5 using namespace std;
     6 
     7 int main()
     8 {
     9     IntArray* a = IntArray::NewInstance(5);   
    10     IntArray* b = IntArray::NewInstance(10);
    11     
    12     if( a && b )
    13     {
    14         IntArray& array = a->self();
    15         IntArray& brray = b->self();
    16         
    17         cout << "array.length() = " << array.length() << endl;
    18         cout << "brray.length() = " << brray.length() << endl;
    19     
    20         array = brray;
    21         
    22         cout << "array.length() = " << array.length() << endl;
    23         cout << "brray.length() = " << brray.length() << endl;
    24     }
    25     
    26     delete a;
    27     delete b;
    28     
    29     return 0;
    30 }

    运行结果如下:

    一般性原则:

    重载赋值操作符,必然需要实现深拷贝。

    编译器默认提供的函数: 

    关于string的疑问:

    我们将s对象转换为char* 指针,然后打印p。然后又将s调用append添加abcde字符,这时我们再打印p指向的字符串,期望输出12345abcde。

    上面片段的运行结果如下:

     这并不是我们想要的结果。

    我们打印s的值是可以得到预期结果的:

    问题分析:

    调用append之后,s内部的字符指针指向了新的内存空间。 而p还指向原来的空间,这块空间起始已经释放了,因此,p是一个野指针。

    我们应该遵循的编程原则是在C++中就采用C++思想,不要混入C语言的思想。不要混合C语言和C++的编程思想。

    运行结果如下:

    程序并没有打印出12345,不符合我们的预期。

    继续试验:

    我们可以看到,s的前五个字符确实是12345,但是18行认为s对象还是空的,我们直接使用cout  << s << endl打印s的话,也是输出空,这是为什么呢?

    问题在于我们用C++来写C语言的程序。

    问题分析:

    s内部维护了一个表示长度的变量,我们用C语言的方式给s对象赋值,根本不会改变这个长度变量,因此,对象本身认为自己还是空的。

    将程序改造如下:

    可以成功打印出12345。

    切记:不要使用C语言的方式操作C++中的字符串。我们应该直接采用C++面向对象的方式来写代码。

    小结:

  • 相关阅读:
    json解析json字符串时候,数组必须对应jsonObjectArray,不能对应JsonObject。否则会解析错误。
    下载Tomcat时Tomcat网站上的core和deployer的区别
    maven中GroupID 和ArtifactID怎么写
    推送知识点3
    推送知识点2
    推送知识点注意事项
    spring mvc超强的json支持,你自己根本不需要额外的配置。spring mvc都给你配置好了!!!
    数据库中的父表和子表相当于代码中的父类和子类继承
    有两个地方,用到了javabean对象和属性字符串值之间的转换
    web接入层 传入参数的格式化及web返回值传出数据的参数格式化,都要统一
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9573218.html
Copyright © 2011-2022 走看看