抽象类和独特的指针

Abstract class and unique pointer

本文关键字:指针 抽象类      更新时间:2023-10-16

我的代码中有以下错误:

error: allocating an object of abstract class type 'Material'

我不知道如何处理这种情况。

我知道std::make_unique执行分配,因此不能分配类型Material的对象,但是我不知道如何纠正它。

#include <iostream>
#include <memory>
struct Material
{
  Material() = default;
  virtual int get_color() const = 0;
};
struct Basic : public Material
{
  Basic() = default;
  virtual int get_color() const override
  {
    return 1;
  }
};
struct Mix : public Material
{
  Mix(const Material& mat1, const Material& mat2)
    : mat1_(std::make_unique<Material>(mat1))
    , mat2_(std::make_unique<Material>(mat2))
  {}
  virtual int get_color() const override
  {
    return mat1_->get_color() + mat2_->get_color();
  }     
private:
  std::unique_ptr<Material> mat1_;
  std::unique_ptr<Material> mat2_;
};
int main()
{
  auto mix = Mix(Basic(), Basic());
  std::cout << mix.get_color() << 'n';
}

此调用:

std::make_unique<Material>(mat1)

试图创建一个Material类的实例,这是mat1类型无关的。您似乎需要班上的方法clone()

class Material {
...
    virtual std::unique_ptr<Material> clone() const = 0;
};

然后Mix CTOR将是:

Mix(const Material& mat1, const Material& mat2)
    : mat1_(mat1.clone())
    , mat2_(mat2.clone())
  {}

您需要在每个派生类中实现clone()

struct Basic : public Material
{
  Basic() = default;
  virtual std::unique_ptr<Material> clone() const override
  {
      return std::make_unique<Basic>( *this ); 
  }
  virtual int get_color() const override
  {
    return 1;
  }
};

问题是因为Mix试图创建一个抽象类Material的对象:

: mat1_(std::make_unique<Material>(mat1))

理想情况下,基于签名

Mix(const Material& mat1, const Material& mat2)

Mix应该能够仅在传递给它的任何类型的Material上操作。

通过抽象类参考传递Mix的事实很好。但是Mix试图创建派生类的对象的事实是不寻常的。如果还有其他派生类怎么办?

我的设计略有不同,使得 Mix不是是成员的所有者。它们是由外面的东西创建和拥有的,Mix只需将传递给它的内容混合。

struct Mix : public Material
{
  Mix(const Material& mat1, const Material& mat2)
    : mat1_{mat1}, mat2_{mat2}
  {}
  virtual int get_color() const override
  {
    return mat1_.get_color() + mat2_.get_color();
  }     
private:
  Material const& mat1_;
  Material const& mat2_;
};
int main()
{
  std::unique_ptr<Material> mat1 = std::make_unique<Basic>();
  std::unique_ptr<Material> mat2 = std::make_unique<Basic>();
  auto mix = Mix(*(mat1.get()), *(mat2.get()));
  std::cout << mix.get_color() << 'n';
}

您可以使用模板构造函数安排构造正确类型的情况,而无需克隆方法:

#include <iostream>
#include <memory>
struct Material {
    Material() = default;
    virtual int get_color() const = 0;
};
struct Basic : Material {
    Basic() = default;
    int get_color() const override {
        return 1;
    }
};
struct Mix : Material {
    template<typename M1, typename M2>
    Mix(const M1& mat1, const M2& mat2)
        : mat1_{std::make_unique<M1>(std::move(mat1))}
        , mat2_{std::make_unique<M2>(std::move(mat2))}
    {} 
    int get_color() const override {
        return mat1_->get_color() + mat2_->get_color();
    }
private:
    std::unique_ptr<Material> mat1_;
    std::unique_ptr<Material> mat2_;
};
int main() {
    auto mix = Mix(Basic(), Basic());
    std::cout << mix.get_color() << 'n';
}

请注意,仅当您发送带有已知类型的材料的实例时才有效。

http://www.cplusplus.com/forum/beginner/236974/包含适当的解决方案。make_sharedmake_unique应为特定类型;然后,您可以在没有问题的情况下将其存储在抽象类型的shared_ptrunique_ptr中。