是否可以在基础 class 中定义复制构造函数并仍然处理派生的 class 情况?

Can a copy constructor be defined in the base class and still handle derived class circumstances?

我有一个 class 结构,如下所示:

class P {
    public:
        virtual std::auto_ptr<P> clone() const=0;
};

class A : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new A(*this));
        }
};

class B : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new B(*this));
        }
};

class C : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new C(*this));
        }
};

这只是复制构造函数的代码:classes ABC 否则都有不同的代码。这里有很多代码重复,能不能简化一下?

使用 CRTP,您可以:

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::auto_ptr<Base> clone() const {
        return std::auto_ptr<Base>(new Derived(static_cast<const Derived&>(*this)));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

为了使派生的实型受益 类,我会将代码修改为:

class P {
public:
    std::auto_ptr<P> clone() const { return std::auto_ptr<P>(vclone()); }
private:
    virtual P* vclone() const = 0;
};

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::unique_ptr<Derived> clone() const {
        return std::unique_ptr<Derived>(static_cast<Derived*>(vclone()));
    }
private:
    // Cannot use covariant-type `Derived*` in CRTP as Derived is not complete yet
    Base* vclone() const {
        return new Derived(static_cast<const Derived&>(*this));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

因此,以下是有效的:

A a;
std::auto_ptr<A> a_copy =  a.clone();

Can a copy constructor be defined in the base class and still handle derived class circumstances?

一般来说,简短的回答是"No"。

如果编译器生成的复制构造函数足够的话,它工作正常。

如果派生 class 的定义使得编译器生成的复制构造函数不合适,则无法避免在派生 class.[=11 中定义一个的需要=]

如果您的意思是是否有一种方法可以为每个派生 class 提供一个克隆方法而无需显式写出:答案是否定的。如果将 metaclasses 添加到 C++ 中,这是可能实现的一件事,但暂时不要指望它会进入该语言。

但是,Boost.Any 可以在不知道动态类型的情况下复制对象,并且可以在 C++03 中实现。如果你愿意,你可以使用类似类型的擦除技术。简而言之,这将包括:

  • 一个ClonablePBaseclass,带有一个虚clone方法和一个虚析构函数
  • 一个从ClonablePBase派生的ClonablePclass模板。 ClonableP<T> 类型的对象(其中 T 派生自 P)拥有一个 T 对象并且知道如何使用 T 的复制构造函数克隆自身。
  • 一个 AnyP class 持有 std::auto_ptr<ClonablePBase>。它通过调用虚拟克隆方法来复制自身。