zoukankan      html  css  js  c++  java
  • 19.C++-(=)赋值操作符、初步编写智能指针

    (=)赋值操作符

    • 编译器为每个类默认重载了(=)赋值操作符
    • 默认的(=)赋值操作符仅完成浅拷贝
    • 默认的赋值操作符和默认的拷贝构造函数有相同的存在意义

    (=)赋值操作符注意事项

    首先要判断两个操作数是否相等

    返回值一定是 return *this; 返回类型是Type&型,避免连续使用=后,出现bug

    比如:

    class Test{
           int *p;
    
           Test(int i)
           {
                  p=new int(i);
           }
    Test
    & operator = (const Test& obj) { if(this!=&obj) { delete p; p=new int(*obj.p); } return *this; } };

    注意:指针对象之间赋值是不会调用(=)复制操作符的

    编译器默认提供的类函数

    包括了:构造函数,析构函数,拷贝构造函数, (=)赋值操作符

    智能指针

    智能指针的由来

    在以前C程序里,使用malloc()等函数动态申请堆空间时,若不再需要的内存没有被及时释放,则会出现内存泄漏,若内存泄漏太多,则会直接导致设备停止运行,特别是嵌入式设备,可能有些设备一上电就要运行好几个月.

    在C++里,为了减少内存泄漏,所以便引出了智能指针

    介绍

    • 智能指针实际上是将指针封装在一个类里,通过对象来管理指针.
    • 构造函数时,通过对象将指针传递进来,指针可以是缺省值.
    • 然后构造-> ” “ * ” “ = 操作符重载,让这个对象拥有指针的特性.
    • 最后通过析构函数,来释放类里的指针.

    注意

    • 智能指针只能指向堆空间中的对象或者变量
    • 并且一片空间最多只能由一个智能指针标识(因为多个指向地址相同的智能指针调用析构函数时,会出现bug)
    • ->和*都是一元操作符,也就是说不能带参数

    比如ptr->value的->:

    当ptr的类型是普通指针类型时,等价于:(*ptr).mem

    当ptr的类型是时,等价于:(ptr.operator->())->value    等价于: ( *(ptr.operator->()) ).value

    所以->操作符函数的返回类型是type*,返回值是一个指针变量本身(不带*)

    具体参考: https://segmentfault.com/q/1010000004620896

    接下来个示例,指向一个int型的智能指针

    #include <iostream>
     
    using namespace std;
    
    class Point{
    int *p; public: Point(int *p=NULL) { this->p = p; } int* operator -> () { return p; } int& operator *() { return *p; } ~Point() { cout<<"~Point()"<<endl; delete p; } }; int main() { for(int i=0;i<5;i++) { Point p=new int(i); cout <<*p<<endl; } return 0; }

    运行打印:

    0
    ~Point()
    1
    ~Point()
    2
    ~Point()
    3
    ~Point()
    4
    ~Point()

    从结果可以看到, Point p每被从新定义之前,便会自动调用析构函数来释放之前用过的内存,

    这样便避免了野指针的出现

    接下来,我们继续完善上面代码,使它能够被赋值.

    #include <iostream>
    using namespace std; class Point{ int *p; public: Point(int *p=NULL) { this->p = p; } bool isNULL() { return (p==NULL); } int* operator -> () { return p; }  
    int& operator *() { return *p; } Point& operator = (const Point& t) { cout<<"operator =()"<<endl; if(this!=&t) { delete p; p = t.p; const_cast<Point&>(t).p=NULL; //去掉const类型参数 } return *this; } ~Point() { cout<<"~Point()"<<endl; delete p; } }; int main() { Point p=new int(2); Point p2; p2= p; //等价于 p2.operator= (p); cout <<"p=NULL:"<<p.isNULL()<<endl; *p2+=3; //等价于 *(p2.operator *())=*(p2.operator *())+3;              //p2.operator *()返回一个int指针,并不会调用Point类的=操作符 cout <<"*p2="<<*p2 <<endl; return 0; }

    运行打印:

    operator =()       
    
    p=NULL:1              // Point  p的成员已被释放
    
    *p2=5
    
    ~Point()
    ~Point()

    但是,还有个缺点,就是这个智能指针仅仅只能指向int类型,没办法指向其它类型. 

    接下来继续修改,通过类模板来使这个智能指针能指向多种类型

    #include <iostream>
    
    using namespace std;
    
    template <typename T>
    class Point
    {
        T *p;
    public:
        Point(T *p)
        {
            this->p = p; 
        }
        bool isNULL()
        {
            return (p==NULL);
        }
        
        T* operator -> ()
        {
            return p; 
        } 
        
        T& operator *()
        {
            return *p; 
        } 
        
        Point& operator = (const Point& t)
        {
                  cout<<"operator =()"<<endl;
    
                  if(this!=&t)
                  {
                         delete p;
                         p = t.p;
                         const_cast<Point&>(t).p=NULL;   //去掉const类型参数
                  }         
                  return *this;
         }
      
        ~Point()
        {
            delete p;    
        } 
    
    };
     
    int main()
    {       
           Point<int> p1=new int(2); 
           cout<<*p1<<endl; 
        
           Point<float> p2=new float(3.56);  
           cout<<*p2<<endl;
           
           return 0;
    }

    运行打印:

    2
    3.56
    ~Point()
    ~Point()
  • 相关阅读:
    MYSQL基础02DML操作数据8
    MYSQL基础02SQL5
    SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)
    SpringSecurity权限管理系统实战—三、主要页面及接口实现
    SpringSecurity权限管理系统实战—九、数据权限的配置
    SpringSecurity权限管理系统实战—八、AOP 记录用户、异常日志
    SpringSecurity权限管理系统实战—六、SpringSecurity整合JWT
    SpringSecurity权限管理系统实战—二、日志、接口文档等实现
    SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)
    SpringSecurity权限管理系统实战—七、处理一些问题
  • 原文地址:https://www.cnblogs.com/lifexy/p/8658605.html
Copyright © 2011-2022 走看看