开发者

Copying a Polymorphic object in C++

开发者 https://www.devze.com 2023-02-13 20:04 出处:网络
I have base-class Base from which is derived Derived1, Derived2 and Derived3. I have constructed an instance for one of the the derived classes which I store as Base* a. I now need to make a deep cop

I have base-class Base from which is derived Derived1, Derived2 and Derived3.

I have constructed an instance for one of the the derived classes which I store as Base* a. I now need to make a deep copy of the object which I will store as Base* b.

As far as I know, the normal way of copying a class is to use copy constructors and to overload operator=. However since I don't know whether a is of type Derived1, Derived2 or Derived3, I cannot开发者_运维百科 think of a way of using either the copy constructor or operator=. The only way I can think of to cleanly make this work is to implement something like:

class Base
{
public:
  virtual Base* Clone() = 0;

};

and the implement Clone in in the derived class as in:

class Derivedn : public Base
{
public:
  Base* Clone() 
  {
    Derived1* ret = new Derived1;
    copy all the data members
  }
};

Java tends to use Clone quite a bit is there more of a C++ way of doing this?


This is still how we do stuff in C++ for polymorphic classes, but you don't need to do the explicit copy of members if you create a copy constructor (possibly implicit or private) for your objects.

class Base
{
public:
  virtual Base* Clone() = 0;
};

class Derivedn : public Base
{
public:
  //This is OK, its called covariant return type.
  Derivedn* Clone() 
  {
    return new Derivedn(*this);
  }
private:
  Derivedn(const Derivedn&) : ... {}
};


template <class T>
Base* Clone (T derivedobj) {
  T* derivedptr = new T(derivedobj);
  Base* baseptr = dynamic_cast<Base*>(derivedptr);
  if(baseptr != NULL) {
    return baseptr;
  }
  // this will be reached if T is not derived from Base
  delete derivedptr;
  throw std::string("Invalid type given to Clone");
}

The only thing this function requires of the derived classes is that their copy constructor is publicly accessible.


I have seen some answers using a template function to clone objects. Let me show you how that will not work. Consider the following code:

This is a special case that shows up when objects are being received from a container of Base objects. The function will return a pointer to the Base even when obj is of type Derived. The template only works when it is called by an object that has not undergone any casting.

#include <iostream>
#include <memory>
#include <vector>

class Base{
public:
    virtual void foo(){}
};

class Derived : public Base{};

template<typename T>  std::shared_ptr<T> foo(const T& obj){
    std::cout << "obj is of type: " << typeid(obj).name() << std::endl;
    std::cout << "T is of type: " << typeid(T).name() << std::endl;
    std::cout << std::endl;
    return std::make_shared<T>(obj); // returns Base pointer
}

int main()
{
    std::vector<std::shared_ptr<Base>> vec {std::make_shared<Base>(), std::make_shared<Derived>()};
    for(auto c: vec)
        foo(*c);

    return 0;
}

/* OUTPUT:
obj is of type: 4Base
T is of type: 4Base

obj is of type: 7Derived
T is of type: 4Base

*/
0

精彩评论

暂无评论...
验证码 换一张
取 消