【问题标题】:Copy constructor: deep copying an abstract class复制构造函数:深度复制抽象类
【发布时间】:2010-12-02 00:22:02
【问题描述】:

假设我有以下情况(简化情况):

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);
}

现在,我有什么方法可以在 Material 的复制构造函数中对抽象 IColor 进行深度复制吗?也就是说,我希望复制任何 m._color 的值(颜色、纹理),而不仅仅是指向 IColor 的指针。

【问题讨论】:

    标签: c++ constructor abstract-class deep-copy


    【解决方案1】:

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        您必须自己将该代码添加到 Material 复制构造函数中。然后编写代码以释放析构函数中分配的 IColor。

        您还需要向 IColor 添加一个虚拟析构函数。

        自动进行深拷贝的唯一方法是直接存储颜色而不是指向 IColor 的指针。

        【讨论】:

        • 因为默认情况下它只会简单地将指针地址复制到复制的指针地址中。它不会复制指向的内容,然后重新调整指针。 Luke 最好的建议是创建从复制构造函数调用的 clone() 函数。
        【解决方案4】:

        为颜色添加一个 clone() 方法可能是最好的,但如果您没有该选项,另一种解决方案是使用 dynamic_cast 将 IColor* 转换为 Color*。然后就可以调用 Color 复制构造函数了。

        【讨论】:

        • 但是你不知道是Color还是Texture,那你怎么dynamic_cast呢?
        • 如果对象不是颜色类型,那么 dynamic_cast(_color) 将返回 null。 (只要类至少有一个虚方法,动态转换/rtti 就可以检测出实际类型是什么)。所以你可以做的是测试可能性。这一点都不好玩,而且几乎总是比使用 clone() 方法更糟糕,但在极少数情况下你必须做这样的事情。
        【解决方案5】:

        如果你有一个为你创建颜色的“类工厂”类,你可以为用户实现一个类型擦除向上转换的复制构造函数。在您的情况下,它可能不适用,但是当它适用时,我发现它比对实施者强制执行克隆功能更优雅。

        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;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-26
          • 1970-01-01
          • 2014-08-04
          相关资源
          最近更新 更多