Abstract class and unique pointer

自古美人都是妖i 提交于 2021-01-21 03:45:10

问题


I have the following error in my code:

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

I don't know how to handle this case.

I'm aware that std::make_unique performs an allocation, so it can't allocate the object of type Material, but I don't know how to correct it.

#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';
}

回答1:


This call:

std::make_unique<Material>(mat1)

tries to create an instance of class Material, it is irrelevant what type mat1 has. You seem to need method clone() in your class:

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

then Mix ctor would be:

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

and you need to implement clone() in every derived class:

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;
  }
};



回答2:


The problem is because Mix tries to create an object of the abstract class Material:

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

Ideally, based on the signature

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

Mix should be able to just operate on any type of Material passed to it.

The fact that Mix is passed with abstract class reference is good. But the fact that Mix is trying to create objects of derived class is unusual. What if there were other derived classes?

I would design slightly differently such that Mix is not the owner of the constituents; they are created and owned by something outside, Mix just mixes what is passed to it.

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';
}



回答3:


You can use a templated constructor to arrange for constructing the right types without needing a clone method:

#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';
}

Note that this works only if you send instance of a material with a known type.




回答4:


http://www.cplusplus.com/forum/beginner/236974/ contains the proper solution. The make_shared should be of the specific type; you can then without issues store this in a unique_ptr of the abstract type.



来源:https://stackoverflow.com/questions/44413478/abstract-class-and-unique-pointer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!