是否可以在基础 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 A
、B
、C
否则都有不同的代码。这里有很多代码重复,能不能简化一下?
使用 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 中实现。如果你愿意,你可以使用类似类型的擦除技术。简而言之,这将包括:
- 一个
ClonablePBase
class,带有一个虚clone
方法和一个虚析构函数
- 一个从
ClonablePBase
派生的ClonableP
class模板。 ClonableP<T>
类型的对象(其中 T
派生自 P
)拥有一个 T
对象并且知道如何使用 T
的复制构造函数克隆自身。
- 一个
AnyP
class 持有 std::auto_ptr<ClonablePBase>
。它通过调用虚拟克隆方法来复制自身。
我有一个 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 A
、B
、C
否则都有不同的代码。这里有很多代码重复,能不能简化一下?
使用 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 中实现。如果你愿意,你可以使用类似类型的擦除技术。简而言之,这将包括:
- 一个
ClonablePBase
class,带有一个虚clone
方法和一个虚析构函数 - 一个从
ClonablePBase
派生的ClonableP
class模板。ClonableP<T>
类型的对象(其中T
派生自P
)拥有一个T
对象并且知道如何使用T
的复制构造函数克隆自身。 - 一个
AnyP
class 持有std::auto_ptr<ClonablePBase>
。它通过调用虚拟克隆方法来复制自身。