zoukankan      html  css  js  c++  java
  • c++第十三章 -(副本构造器)

    • 逐位复制(bitwise copy):编译器将生成必要的代码把“源”对象各属性的值分别赋值给“目标”对象的对应成员的行为。对象的地址赋值操作,于是乎,当删除一个对象时,它包含的指针也将被删除,但万一此时另一个副本(对象)还在引用这个指针,就会出问题!
    • 要是程序员在当初进行对象“复制”时能够精确地表明应该复制些什么和如何赋值,那就理想了。为解决该问题,我们可以对=操作符进行重载,其中对指针进行处理:MyClass &operator= (const MyClass &rhs);该语句的意思是表明这个方法所预期的输入参数应该是一个MyClass类型的、const常量不可改变的引用,并返回一个引用,该引用指向一个MyClass类的对象。

    对赋值操作符重载的Demo:

    class MyClass
    {
    public:
        MyClass(int *p);
        ~MyClass();
        
        MyClass &operator=(const MyClass &rhs);
        void print();
    private:
        int *ptr;
    };
    
    MyClass::MyClass(int *p)
    {
        ptr = p;
    }
    
    MyClass::~MyClass()
    {
        delete ptr;
    }
    
    //MyClass a(1);MyClass(2);a = b;在这里已经对=操作符进行了重载
    MyClass &MyClass::operator=(const MyClass &rhs)//传入一个const常量地址
    {
        if (this != &rhs)
        {
            delete ptr;//删除掉a对象原有的ptr成员
            
            ptr = new int;//重新申请一块内存,表明了,现在有两个指针指向的地址是不一样滴,解决了2个指向指向同一块地址的问题
            *ptr = *rhs.ptr;//将传进来对象的值赋值给ptr
        }
        else
        {
            std::cout << "赋值号两边为同个对象,不做处理!
    ";//
        }
        return *this;
    }
    
    void MyClass::print()
    {
        std::cout << *ptr << std::endl;
    }
    
    int main(int argc, const char * argv[])
    {
        MyClass obj1(new int(1));
        MyClass obj2(new int(2));
        
        obj1.print();
        obj2.print();
        
        obj2 = obj1;//这里=号已经重载了
        
        obj1.print();
        obj2.print();
        
        return 0;
    }

    控制台输出结果:

    1
    2
    1
    1

    副本构造器何时被调用?当创建一个实例对象obj1,然后再创建实例obj2的同时用obj1的值对它进行初始化,此时,编译器将在MyClass类里寻找一个副本构造器(copy constructor),如果找不到,它会自行创建一个。即使我对之前的=操作符进行了重载,但由编译器(系统)创建的副本构造器仍以“逐位复制”的方法把obj1赋值给obj2。换句话说就是我们对=操作符进行了重载,“逐位复制”的行为仍然会发生。然而这个时候,我们就须要自定义一个副本构造器:MyClass(const MyClass &rhs);

    副本构造器Demo:

    class MyClass
    {
    public:
        MyClass(int *p);
        MyClass(const MyClass &rhs);//副本构造器
        ~MyClass();
        
        MyClass &operator= (const MyClass &rhs);
        void print();
    private:
        int *ptr;
    };
    
    MyClass::MyClass(int *p)
    {
        std::cout << "进入构造器
    ";
        ptr = p;
    }
    MyClass::MyClass(const MyClass &rhs)
    {
        std::cout << "进入副本构造器
    ";
        *this = rhs;//这里的=操作符已经被重载了
    }
    MyClass::~MyClass()
    {
        std::cout << "进入析造器
    ";
        delete ptr;
    }
    MyClass &MyClass::operator=(const MyClass &rhs)
    {
        std::cout << "进入赋值语句重载
    ";
        if (this != &rhs)
        {
            delete ptr;
            
            ptr = new int;
            *ptr = *rhs.ptr;
        }
        else
        {
            std::cout << "赋值号两边为同个对象,不做处理!
    ";//
        }
        return *this;
    }
    void MyClass::print()
    {
        std::cout << *ptr << std::endl;
    }
    int main(int argc, const char * argv[])
    {
        MyClass obj3(new int(3));
        MyClass obj4 = obj3;//
    
        obj3.print();
        obj4.print();
        
        return 0;
    }

    控制台输出:

    进入构造器
    进入副本构造器
    进入赋值语句重载
    3
    3
    进入析造器
    进入析造器
  • 相关阅读:
    查询记录时rs.previous()的使用
    Cocos2d-x中由sprite来驱动Box2D的body运动(用来制作平台游戏中多变的机关)
    vim经常使用命令总结
    微信公众号:码农的世界
    RHEL5 X86-64上安装Oracle 11gR2演示样例与总结
    JavaScript中获取当前项目的绝对路径
    thinkphp内置标签简单讲解
    function $(id) {}表示什么函数
    表单实例(判断两次密码是否一致)
    thinkphp模板继承
  • 原文地址:https://www.cnblogs.com/huen/p/3837262.html
Copyright © 2011-2022 走看看