我们可以声明一个抽象方法来返回抽象超类中的子类对象而不需要新的实例化吗?

Posted

技术标签:

【中文标题】我们可以声明一个抽象方法来返回抽象超类中的子类对象而不需要新的实例化吗?【英文标题】:Can we declare a abstract method to return subclass objects in abstract superclass without new instantiation? 【发布时间】:2019-11-03 14:04:06 【问题描述】:

我想构建一个类(例如 VectorSpace),该类将抽象地存在某些方法。 我最近从 Java 迁移到 C++,我在尝试改写 Java 中的通用抽象方法声明时遇到了问题

情况是c++不允许声明如: 抽象类方法名(...) = 0; 另一方面,Java 允许返回类型是抽象类。 这在 c++ 中是不允许的,编译会导致错误说抽象类不能作为方法的返回类型。 我浏览了这个页面:returning an abstract class from a function。 所以我在 C++ 中做了以下操作:

//Fields are any classes which +,* defined on them
  template<class F> class VectorSpace
  
    virtual VectorSpace<F>* operator+(const VectorSpace<F>& el) const =0;
    virtual VectorSpace<F>* operator-() const =0;
    virtual VectorSpace<F>* operator*(const F& el) const =0;
    ....
  ;
  class Vector : public VectorSpace<double>
  
      ....
      Vector* operator+(const VectorSpace<double>& el) const return new Vector(....);
  

但是,这样做的问题是,每当应用任何运算符(例如 +、-)时,我都将使用“new”为作为 VectorSpace 子类的任何类(如 Vector)实例化一个对象,这必须手动删除。

有没有办法解决这个问题?

【问题讨论】:

你可以返回一个引用,但是VectorSpace&lt;F&gt; 必须在某个地方;如果您返回对临时对象的引用(并且您使用 operator + 表明您将返回临时对象),您将遇到其他问题。 为什么叫它VectorSpace?它的字面意思是从 VectorSpace 派生的类的对象将是向量空间,而不是向量。 这看起来像是在将 Java 设计强制为 C++。在不知道要解决的问题的情况下,总是很难确定,但在 C++ 中,我们可能会模板化使用 VectorSpace 的地方,而不是将 VectorSpace 设为抽象类。 运算符真的需要是虚拟的还是它们实际上会有相同的实现?在这些情况下有两种不同的解决方案。 【参考方案1】:

你可以有另一个类,比如VectorWrapper,它包装了一个指向抽象类的指针,例如通过std::unique_ptr&lt;VectorSpace&lt;double&gt; &gt;。在此类中,您可以重载operator+ 以将调用重定向到实现,然后返回一个新的本地构造的包装器。 std::unique_ptr 设施避免了手动删除,并且您拥有按值返回的重载运算符 - 因此它们易于使用。请注意,运算符 newdelete 仍然在后台调用并由 VectorWrapper 封装。

class VectorWrapper 

    VectorWrapper(std::unique_ptr<VectorSpace<double> > ptr)
        : m_impl(std::move(ptr))
    
    VectorWrapper operator+(const VectorWrapper& other)
    
         return VectorWrapper(*m_impl + *other.m_impl);
    
private:
    std::unique_ptr<VectorSpace<double> > m_impl;
;

它与类型擦除 C++ 习语密切相关。

编辑:你还需要实现复制构造函数和赋值来调用std::make_unique 等。或者如果向量是不可变的——就像数学对象一样——你可以考虑使用std::shared_ptr,但它可能会更慢取决于在您的代码中复制 VectorWrapper 的频率。

【讨论】:

以上是关于我们可以声明一个抽象方法来返回抽象超类中的子类对象而不需要新的实例化吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用超类中声明的方法返回子类的实例? [复制]

java--面向对象重点

2017-09-20

在抽象超类的静态方法中创建子类的实例? [复制]

抽象类

抽象和接口