简体   繁体   English

复制构造函数:深度复制抽象类

[英]Copy constructor: deep copying an abstract class

Suppose I have the following (simplified case):假设我有以下(简化的情况):

class Color;

class IColor
{
public: 
    virtual Color getValue(const float u, const float v) const = 0;
};

class Color : public IColor
{
public:
    float r,g,b;
    Color(float ar, float ag, float ab) : r(ar), g(ag), b(ab) {}
    Color getValue(const float u, const float v) const 
    { 
        return Color(r, g, b)
    }
}

class Material
{
private:
    IColor* _color;
public:
    Material();
    Material(const Material& m);
}

Now, is there any way for me to do a deep copy of the abstract IColor in the copy constructor of Material?现在,有什么方法可以让我在 Material 的复制构造函数中对抽象 IColor 进行深层复制吗? That is, I want the values of whatever m._color might be (a Color, a Texture) to be copied, not just the pointer to the IColor.也就是说,我希望复制任何 m._color 的值(颜色、纹理),而不仅仅是指向 IColor 的指针。

你可以在你的界面中添加一个 clone() 函数。

You'll have to add that code yourself to the Material copy constructor.您必须自己将该代码添加到 Material 复制构造函数中。 Then code to free the allocated IColor in your destructor.然后编码以释放析构函数中分配的 IColor。

You'll also want to add a virtual destructor to IColor.您还需要向 IColor 添加一个虚拟析构函数。

The only way to do a deep copy automatically would be to store a color directly instead of a pointer to an IColor.自动进行深度复制的唯一方法是直接存储颜色而不是指向 IColor 的指针。

Adding a clone() method to color is probably best, but if you don't have that option, another solution would be to use dynamic_cast to cast IColor* to Color*.将 clone() 方法添加到颜色可能是最好的,但如果您没有该选项,另一种解决方案是使用 dynamic_cast 将 IColor* 转换为 Color*。 Then you can invoke the Color copy constructor.然后您可以调用 Color 复制构造函数。

If you have a "factory like" class that creates Colors for you, you can implement a type erased upcasting copy constructor for the user.如果您有一个为您创建颜色的“类似工厂”的类,您可以为用户实现一个类型擦除的向上复制构造函数。 In your case, it probably doesn't apply, but when it does I find it more elegant than enforcing a clone function on implementers.在您的情况下,它可能不适用,但是当它适用时,我发现它比对实现者强制执行克隆功能更优雅。

struct IColor {
    /* ... */

    // One way of using this.
    // If you have a "manager" class, then this can be omitted and completely
    // hidden from IColor implementers.
    std::unique_ptr<IColor> clone() const final {
        return cpy_me(this); // upcasts
    }

    // There are other ways to riff around the idea, but the basics are the same.

private:
    friend struct ColorMaker;

    IColor() = default;

    using cpy_callback_t = std::unique_ptr<IColor> (*)(const IColor*);
    cpy_callback_t cpy_me = nullptr;
};

struct ColorMaker {
    template <class T>
    static std::unique_ptr<IColor> make_color() {
        static_assert(std::is_base_of_v<IColor, T>, "bleep bloop, no can do");

        std::unique_ptr<IColor> ret = std::make_unique<T>();

        // Encoding type T into the callback, type-erasing it.
        // IColor implementer only has to implement copy constructor as usual.
        ret.cpy_me = [](const IColor* from) -> std::unique_ptr<IColor> {
            return std::make_unique<T>(*static_cast<const T*>(from));
        };

        return ret;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM