如何避免 c++ 中多态对象的 clone() 样板代码

发布于 2024-11-14 22:28:59 字数 1173 浏览 1 评论 0原文

如果我想在C++中克隆一个多态对象(即从其他类B派生的类A的实例),最简单的方法似乎是给B一个虚拟克隆成员函数,它必须被A覆盖并且看起来像这样

A* clone(){
    return new A(*this);
}

我的问题是,我发现这个不必要的样板代码,因为如果想使用 C++ 的运行时多态特性,这几乎总是需要的。如何规避?

谢谢

为什么我需要这个:

我的用例可以抽象为以下示例: 我有一个 Integral 类,它计算某个函数的积分。这样做,他们有一个成员,它是指向 MathFunction 类的指针。这个抽象类包含一个纯虚函数evaluate,它接受一个参数。我想要实现幂函数,我将创建一个类 PowFunction : class MathFunction。该类将有一个成员exponent,并且函数评估将如下所示:

double evaluate(x){
    return pow(x,exponent);
}

如前所述,class Integral 的成员MathFunction 必须是多态的,这要求它是一个指针。用另一个问题来回答评论者的问题。为什么我不希望能够复制 MathFunction 对象?

我真的希望 Integral “拥有”它的 MathFunction,这意味着它可以更改参数(如指数)而不更改任何其他 Integral 对象的 MathFunction。这意味着每个 Integral 都需要有自己的副本。这需要 MathFunctions 的 clone() 函数,不是吗?

我想到的一种替代方案是:如果多个 Integral 对象可以通过指向同一地址的指针共享相同的 MathFunction,我可以创建 Integral 对象的副本,而无需复制 MathFunction。但在这种情况下,我必须将所有属性设为常量或以某种方式只读,这也不是很优雅。另外,哪个 Integral 对象应该处理删除 MathFunction 对象?

为什么需要这个:

您是认真地说,一旦使用多态对象,就不再需要复制操作吗?在这方面,多态对象与其他对象有何不同?

使用此论证,您还可以将复制构造函数和复制赋值运算符从 C++ 标准中剔除!

If I want to clone a polymorphic object in C++ (i.e. an instance of a class A which is derived from some other class B), the easiest way seems to give B a virtual clone member function, that has to be overridden by A and looks like this

A* clone(){
    return new A(*this);
}

My problem is, that I find this unnecessary boilerplate code, as this is almost always needed, if one wants to use run-time polymorphic features of C++. How can it be circumvented?

Thanks

Why I need this:

My use case can be abstracted to the following example:
I have a class Integral, which evaluates the integral of some function. Do do this, they have a member which is a pointer to the class MathFunction. This abstract class contains a pure virtual function evaluate which takes one argument. I I wanted to implement the power function I would create a class PowFunction : class MathFunction. This class would have a member exponent and the function evaluate would look like this:

double evaluate(x){
    return pow(x,exponent);
}

As stated the member MathFunction of class Integral has to be polymorhpic, which requires it to be a pointer. To answer the questions of the commenters with another question. Why wouldn't I want to be able to make copies of MathFunction objects?

I really want the Integral to "own" its MathFunction, meaning, that it can alter the parameters (like exponent) without changing the MathFunction of any other Integral object. This means every Integral needs to have its own copy. This requires a clone() function for MathFunctions, doesn't it?

One alternative i thought of: If several Integral objects can share the same MathFunction via a pointer to the same address, I could create copies of Integral objects without the need to copy the MathFunction. But in this case I would have to make all the properties const or somehow readonly, which is not very elegant either. Also, which Integral object should handle delete the MathFunction object?

Why you need this:

Are you seriously saying, that as soon as you work with polymorphic objects you don't ever need a copy operation? What makes polymorphic object different from other objects in this respect?

Using this argumentation, you could also throw the copy constructor and copy assignment operator out of the C++ standard!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

給妳壹絲溫柔 2024-11-21 22:29:00

减少克隆多态对象的需要。确实,我很少在自己的代码中发现这种需要,并且对该问题的评论表明,我并不是唯一一个认为如果您发现自己克隆了所有内容,那么您可能设计错误的人。

当然,为了避免无益,您确实可以使用奇怪的重复模板模式。

template<typename T> struct Clone {
    virtual T* clone() { return new T(static_cast<const T&>(*this)); }
};

Reduce the need to clone polymorphic objects. Really, I rarely find the need for this in my own code, and the comments on the question suggest that I'm hardly alone in the opinion that if you find yourself cloning everything, you're probably designing it wrong.

Of course, never to be unhelpful, you could indeed use the Curiously Recurring Template Pattern.

template<typename T> struct Clone {
    virtual T* clone() { return new T(static_cast<const T&>(*this)); }
};
梦晓ヶ微光ヅ倾城 2024-11-21 22:29:00

我用宏处理了这个问题......它很丑陋,但它可以避免不一致。

/** An interface that can be inherited by any class that wants to provide a Clone()
  * method that will return a copy of itself.
  */
class ICloneable
{
public:
   ICloneable() {}
   virtual ~ICloneable() {}

   virtual ICloneable * Clone() const = 0;
};
#define DECLARE_STANDARD_CLONE_METHOD(class_name) virtual ICloneable * Clone() const {new class_name(*this);}

[...]
public MyCloneableClass : public ICloneable
{
public:
   MyCloneableClass() {}

   DECLARE_STANDARD_CLONE_METHOD(MyCloneableClass);
};

I handled this issue with a macro... it's ugly, but it works to avoid inconsistencies.

/** An interface that can be inherited by any class that wants to provide a Clone()
  * method that will return a copy of itself.
  */
class ICloneable
{
public:
   ICloneable() {}
   virtual ~ICloneable() {}

   virtual ICloneable * Clone() const = 0;
};
#define DECLARE_STANDARD_CLONE_METHOD(class_name) virtual ICloneable * Clone() const {new class_name(*this);}

[...]
public MyCloneableClass : public ICloneable
{
public:
   MyCloneableClass() {}

   DECLARE_STANDARD_CLONE_METHOD(MyCloneableClass);
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文