【C++】多态对象拷贝

使用多态时,通过Base的指针或引用指向具体子类。在容器中,以Base类型存储,比如:vector<Base*> vec

我现在期望对vec中的每个对象,都按照其【实际的类型】进行拷贝,怎么做?拷贝构造函数又不可以设为virtual,从而进行多态实施具体行为。

  • 设一个virtual Clone(),让具体的类自己负责自己具体的类型。这是多态拷贝的标准解决方案

  • 析构函数一定要设为virtual

  • 这是原型模式(prototype pattern)的思想

  • C++支持协变返回类型

    也就是virtual Clone接口,可以返回具体类型的指针或引用,而不是只返回Base*

    • C++允许的协变返回类型仅限于原始指针和引用,不适用于智能指针

    • 智能指针和协变两者不兼容的话,在安全性(裸指针or智能指针)、类型信息缺失之间做选择,该如何取舍?

      以安全性为前提,优先使用智能指针,类型信息可通过dynaminc_cast转。

      如果类型是当前关键需求,必须使用协变,可使用【裸指针+RAII】的方式,在类析构里

    class Base
    {
        virtual Base* Clone()=0;	//定义Clone接口
    }
    
    class Son1:public Base
    {
        Son1(){}
        Son1(const Son1& another){}	//拷贝构造
        
        //virtual Base* Clone() const override
    	virtual Son1* Clone() const override   //C++支持协变返回类型,可以返回更具体的指针,返回Son1*而不是Base*
        {
            return new Son1(*this);	//将当前对象传给本类的拷贝构造,从而返回一个本类的深拷贝对象
        }
    }
    
    class Son2:public Base
    {
        Son2(){}
        Son2(const Son2& another){}	//拷贝构造
        
        virtual Son2* Clone() const override
        {
            return new Son2(*this);	
        }
    }
    
    int main()
    {
        std::vector<Base*> vec;
        vec.push_back(new Son1);
        vec.push_back(new Son2);
        
        std::vector<Base*> vecCopy;
        for(const auto& item:vec)
        {
            vecCopy.push_back(item.Clone());	//返回深拷贝对象,push_back到vecCopy中
        }
    }
    
  • 使用智能指针管理所有权

    防止Clone()中new出来的对象忘记delete。

    class Base
    {
        virtual std::unique_ptr<Base> Clone() const = 0;	
    }
    
    class Son1:public Base
    {
        Son1(){}
        Son1(const Son1& another){}	
        
    	virtual std::unique_ptr<Base> Clone() const override   //不能写成std::unique_ptr<Son1>,智能指针不支持协变
        {
            //unique_ptr不允许拷贝,但编译器允许返回右值的unique_ptr。而c++中规定:return的局部变量当作右值处理
            //因此返回的是一个右值unique_ptr对象,传入到vec::push_back时,由于C++11起push_back(所有stl容器的插入接口)
            //有了参数为右值的重载:push_back(T&& value)触发push_back的移动
            return std::make_unique<Son1>(*this);	
        }
    }
    
    class Son2:public Base
    {
        Son2(){}
        Son2(const Son2& another){}	
        
        virtual std::unique_ptr<Base> Clone() const override
        {
             return std::make_unique<Son2>(*this);	
        }
    }
    
    int main()
    {
        std::vector<std::unique_ptr<Base>> vec;
        vec.push_back(std::make_unique<Son1>());
        vec.push_back(std::make_unique<Son2>());
        
        std::vector<std::unique_ptr<Base>> vecCopy;
        for(const auto& item:vec)
        {
            vecCopy.push_back(item->Clone());	//返回右值unique_ptr,调用右值重载
        }
    }
    
  • CRTP

posted @ 2026-02-13 17:32  仰望星河Leon  阅读(1)  评论(0)    收藏  举报