• c++ 拷贝构造函数、拷贝运算符、析构函数


    拷贝构造函数、拷贝运算符、析构函数

    拷贝构造函数、拷贝运算符、析构函数

    定义行为像值的类

    class HasPtr{
        public:
            HasPtr(const string &s = string()):ps(new string(s)), i(0) {
                cout<<"HasPtr(const string &s = string())"<<endl;
            }
            HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) {
                cout<<"HasPtr(const HasPtr &hp)"<<endl;
            }
            HasPtr &operator=(const HasPtr &hp) {
                auto tmp = new string(*hp.ps); // 右侧对象拷贝到临时变量,考虑自己拷贝自己的情况。
           delete ps;                     // 析构左侧对象
            ps = tmp;
                i = hp.i;
                cout<<"HasPtr &operator="<<endl;
                return *this;
            }
            
            HasPtr testCopy(HasPtr hp) {
                return hp;
            }
            
            HasPtr &testCopy1(HasPtr &hp) {
                return hp;
            }
            
            ~HasPtr() {
                cout<<"~HasPtr()"<<endl;
            }
            
            void print() {
                cout<<*ps<<endl;
            }
            
            void setPs(const string &str) {
                *ps = str;
            }
            
        private:
            string *ps;
            int i;
    };
    

    测试代码

    HasPtr hp("hello");                // 调用构造函数,输出HasPtr(const string &s = string())
    HasPtr hp1 = hp;                   // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
    HasPtr hp2;                        // 调用构造函数,输出HasPtr(const string &s = string())
    hp2 = hp;                          // 调用拷贝运算符函数,输出HasPtr &operator=
    hp1.setPs("word");                 // 构造函数、拷贝构造函数、拷贝赋值运算符函数都为ps分配了新空间
    hp.print();                        // 所以hp、hp1、hp2的ps指针指向的空间不一样,修改一个的值其他的不变。
    hp1.print();                       // 输出word,由setPs函数修改
    hp2.print();                       // 输出hello,值从hp拷贝过来,空间是新分配的。
    // 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
    hp.testCopy(hp1);                  // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
    hp.testCopy1(hp1);                 // 都是引用初始化,不需要调用拷贝构造函数。
    HasPtr *hp_ptr = new HasPtr;       // 调用构造函数
    vector<HasPtr> vec;                // 调用vector的默认构造函数。
    vec.push_back(hp);                 // 调用拷贝构造函数
    
    // 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,但是hp_ptr指向的空间不会被销毁。
    

    定义行为像指针的类

    class HasPtr{
        public:
            // 构造函数,为指针指向分配空间(整个类也只在这个地方分配空间),use初始化为1
            HasPtr(const string &s = string()):ps(new string(s)), i(0) ,use(new size_t(1)){ 
                cout<<"HasPtr(const string &s = string())-->use"<<*use<<endl;
            }
            
            // 拷贝构造函数,只拷贝指针,use值递增
            HasPtr(const HasPtr &hp) :ps(new string(*hp.ps)), i(hp.i) ,use(hp.use){         
                ++*use;
                cout<<"HasPtr(const HasPtr &hp)-->use"<<*use<<endl;
            }
            
            // 拷贝赋值运算符,左侧use递减,当use为0,释放左侧指针指向空间,拷贝右侧数据和指针到左侧对象,use递增。
            HasPtr &operator=(const HasPtr &hp) {
                if(--*use == 0) {
                    delete ps;
                    delete use;
                }
                ++*hp.use;
                ps = hp.ps;
                use = hp.use;
                i = hp.i;
                cout<<"HasPtr &operator=-->use"<<*use<<endl;
                return *this;
            }
            
            HasPtr testCopy(HasPtr hp) {
                return hp;
            }
            
            HasPtr &testCopy1(HasPtr &hp) {
                return hp;
            }
            
            // 析构函数,递减use,当use为0,释放指针指向空间。
            ~HasPtr() {
                if(--*use == 0){
                    delete ps;
                    delete use;
                }
                cout<<"~HasPtr()-->use"<<*use<<endl;
            }
            
            void print() {
                cout<<*ps<<endl;
            }
            
            void setPs(const string &str) {
                *ps = str;
            }
            
        private:
            string *ps;    // 共享,只有构造函数分配,最后一次析构函数销毁
            int i;         // 每个对象独享,每次构造函数、拷贝构造函数、拷贝运算符都分配,每次析构都销毁
            size_t *use;   // 共享,只有构造函数分配,最后一次析构函数销毁
    };
    

    测试程序

    HasPtr hp("hello");                // 调用构造函数,输出HasPtr(const string &s = string())
    HasPtr hp1 = hp;                   // 调用拷贝构造函数,输出HasPtr(const HasPtr &hp)
    HasPtr hp2;                        // 调用构造函数,输出HasPtr(const string &s = string())
    hp2 = hp;                          // 调用拷贝运算符函数,输出HasPtr &operator=
    hp1.setPs("word");                 // 拷贝构造函数、拷贝赋值运算符不为指针ps和use分配新空间
    hp.print();                        // 所以hp、hp1、hp2的ps指针指向相同的空间,修改一个的值其他的也变。
    hp1.print();                       // 输出word,由setPs函数修改
    hp2.print();                       // 输出word,由setPs函数修改
    // 实参初始化形参要调用一次拷贝构造函数,形参初始化返回的临时变量也要调用一次拷贝构造函数,
    hp.testCopy(hp1);                  // 形参和临时变量在函数结束时时要销毁,调用两次析构函数。
    hp.testCopy1(hp1);                 // 都是引用初始化,不需要调用拷贝构造函数。
    HasPtr *hp_ptr = new HasPtr;       // 调用构造函数
    vector<HasPtr> vec;                // 调用vector的默认构造函数。
    vec.push_back(hp);                 // 调用拷贝构造函数
    
    // 接下来要销毁hp,hp1,hp2和vector中的HasPtr的元素,要调用4次析构函数,只有最后一次调用析构函数才会释放ps和use指向的空间。
    // 但是hp_ptr指向的空间不会被销毁。
    

  • 相关阅读:
    Shell学习笔记 ——第一天
    Myclipse 安装 Maven遇见的N个异常
    Myeclipse 创建 Web Maven项目
    Guava API
    String 转Map(基于Guava类库)
    Mybatis——helloWorld级程序
    redis
    listener、context、filter、servlet及其加载顺序
    junit 单元测试
    hibernate —— 树状存储
  • 原文地址:https://www.cnblogs.com/yuandonghua/p/15636037.html
Copyright © 2020-2023  润新知