• 第36课 经典问题解析三


    1. 关于赋值的疑问

    (1)疑问

      ①编译器每个类默认重载了赋值操作符

      ②默认的赋值操作符仅完成浅拷贝

      ③当需要进行深拷贝必须重载赋值操作符

      ④赋值操作符拷贝构造函数相同的存在意义

    【编程实验】默认赋值操作符重载   36-1.cpp

    #include <iostream>
    
    using namespace std;
    
    class Test
    {
    
        int* m_pointer;
    
     public:
    
         Test(){ m_pointer = NULL; }
    
         Test(int i){m_pointer = new int(i);}
    
         Test(const Test& obj){ m_pointer = new int(*obj.m_pointer);}
    
        
         //赋值4个注意点:
    
         //1.返回值为引用。2.参数是const引用的对象
    
         //3.避免自赋值(this!=&obj)。4.返回时*this;
         Test& operator = (const Test& obj)
         {
    
             if( this != &obj)
             {
    
                 delete m_pointer;
    
                 m_pointer = new int(*obj.m_pointer);
    
             }  
    
             return *this;
         }
    
       
         void print()
         {
             cout << "m_pointer = " << hex << m_pointer << endl;
         }    
    
         ~Test(){delete m_pointer;}
    
    };
    
     
    
    int main()
    {
    
        Test t1 = 1;//Test(int i);
    
        Test t2;    //Test();
    
    
        t2 = t1;    //operator=,赋值操作符
    
        t1.print();  //t1.m_pointer != t2.m_pointer;
    
        t2.print();  //
    
        return 0;
    }

    运行结果:

    问题分析:

          

    一般性原则重载赋值操作符,必然需要实现深拷贝!!!

    【编程实验】数组类的优化   IntArray

    //IntArray.h

    #ifndef _INTARRAY_H_
    #define _INTARRAY_H_
    
    class IntArray
    {
    private:
        int m_length;
        int* m_pointer;
        
        IntArray(int len);
        IntArray(const IntArray& obj);
        bool construct();
    public:
        static IntArray* NewInstance(int length); 
        int length();
        bool get(int index, int& value);
        bool set(int index ,int value);
        int& operator [] (int index);
        IntArray& operat
    or = (const IntArray& obj);
        IntArray& self();
        ~IntArray();
    };
    
    #endif

    //IntArray.cpp

    #include "IntArray.h"
    
    IntArray::IntArray(int len)
    {
        m_length = len;
    }
    
    bool IntArray::construct()
    {
        bool ret = true;
        
        m_pointer = new int[m_length];
        
        if( m_pointer )
        {
            for(int i=0; i<m_length; i++)
            {
                m_pointer[i] = 0;
            }
        }
        else
        {
            ret = false;
        }
        
        return ret;
    }
    
    IntArray* IntArray::NewInstance(int length) 
    {
        IntArray* ret = new IntArray(length);
        
        if( !(ret && ret->construct()) ) 
        {
            delete ret;
            ret = 0;
        }
            
        return ret;
    }
    
    int IntArray::length()
    {
        return m_length;
    }
    
    bool IntArray::get(int index, int& value)
    {
        bool ret = (0 <= index) && (index < length());
        
        if( ret )
        {
            value = m_pointer[index];
        }
        
        return ret;
    }
    
    bool IntArray::set(int index, int value)
    {
        bool ret = (0 <= index) && (index < length());
        
        if( ret )
        {
            m_pointer[index] = value;
        }
        
        return ret;
    }
    
    int& IntArray::operator [] (int index)
    {
        return m_pointer[index];
    }
    
    IntArray& IntArray::operator = (const IntArray& obj)
    {
        if( this != &obj )
        {
            int* pointer = new int[obj.m_length];
            
            if( pointer )
            {
                for(int i=0; i<obj.m_length; i++)
                {
                    pointer[i] = obj.m_pointer[i];
                }
                
                m_length = obj.m_length;
                delete[] m_pointer;
                m_pointer = pointer;
            }
        }
        
        return *this;
    }
    
    IntArray& IntArray::self()
    {
        return *this;
    }
    
    IntArray::~IntArray()
    {
        delete[]m_pointer;
    }

    //main.cpp

    #include <iostream>
    
    #include "IntArray.h"
    
     
    
    using namespace std;
    
     
    
    int main()
    
    {
    
        IntArray* a = IntArray::NewInstance(5);
    
        IntArray* b = IntArray::NewInstance(10);
    
     
    
        if(a && b)
    
        {
    
            IntArray& array = a->self();
    
            IntArray& brray = b->self();
    
           
    
            cout << "array.length() = " << array.length() << endl; //5      
    
            cout << "brray.length() = " << brray.length() << endl; //10
    
     
    
            array = brray; //赋值
    
     
    
            cout << "array.length() = " << array.length() << endl; //10      
    
            cout << "brray.length() = " << brray.length() << endl; //10       
    
        } 
    
       
    
        delete a;
    
        delete b;
    
       
    
        return 0;
    
    }

    运行结果:

    (2)编译器默认提供的函数

    • 不带参的构造函数

    • 拷贝构造函数

    • 默认的赋值操作符

    • 析构函数

        

    (3)一般原则重载赋值操作符,必然需要实现深拷贝!!!

    2. 关于string的疑问

    (1)string类内部维护一个指向数据的char*指针(m_cstr),这里用于存放字符串数据的堆空间地址。因字符串操作(如复制、合并、追加等),

    所以这个指针可能在程序运行的过程中发生改变

    【编程实验】字符串问题1   36-2.cpp

    #include <iostream>
    
     
    
    using namespace std;
    
     
    
    int main()
    {
    
        string s = "12345";
    
      
        //程序试图在C的方式访问字符串(不建议这样用!)
        const char* p = s.c_str();//c_str表示C方式的字符串
     
        cout << p << endl; //打印12345
    
        s.append("abcde"); //p成为野指针,因为追加字符串,可能
    
                           //导致堆内存的重新分配,从而m_cstr
    
                           //指的堆内存地址改变了,但p并不知道!
    
                          
        cout << p << endl;  //仍然指向旧的地址(野指针) 
    
       
    
        return 0;
    
    }

    运行结果:

    问题分析:

        

    (2)string类内部维护了一个m_length的变量,用于指示字符串中字符的个数。当使用C的方式使用string对象时,这个m_length可能不会自动更新

    【编程实验】字符串问题2   36-3.cpp

    #include <iostream>
    
     
    
    using namespace std;
    
     
    
    int main()
    {
    
        const char* p = "12345";
    
        string s = ""; //s.length==0
    
        //保留一定量内存以容纳一定数量的字符
        s.reserve(10);//s.length ==0;
    
        //不要使用C语言的方式操作C++中的字符串
        for(int i=0; i < 5; i++)
        {
    
            s[i] = p[i];//注意,虽然此时s对象中的字符串内存
    
                        //确实被赋新的值了。但用这种方式赋值
    
                        //相等于只是通过指针赋值,s.length不
    
                        //会自动更新,即仍为0
    
        }
    
       
    
        cout << s.length() << endl; //0
    
        cout << s.empty() << endl;  //1
    
        cout << s << endl;  //这里将不会有任何输出,因为s.length=0;
    
       
    
        return 0;
    
    }

    运行结果:

    问题分析:

          

    3. 小结

    (1)在需要进行深拷贝的时候必须重载赋值操作符

    (2)赋值操作符拷贝构造函数同等重要的意义

    (3)string通过一个数据空间保存字符数据

    (4)string通过一个成员变量保存当前字符串的长度

    (5)C++开发尽量避开C语言中惯用的编程思想

  • 相关阅读:
    ShaderLab 枚举常量
    PHP to .NET Compiler
    填充圆算法
    战争迷雾
    A*
    寻路算法
    Unity中将动画片段保存为文件
    令人蛋疼的错误提示 0xcdcdcdcd ,0xdddddddd ,0xfeeefeee ,0xcccccccc ,0xabababab
    2D光照
    Rider 2018 激活码
  • 原文地址:https://www.cnblogs.com/hoiday/p/10166401.html
Copyright © 2020-2023  润新知