抽象类和唯一指针

问题描述 投票:7回答:4

我的代码中出现以下错误:

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';
}
c++ inheritance constructor c++14 abstract-class
4个回答
12
投票

这个电话:

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

3
投票

问题是因为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';
}

2
投票

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

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

请注意,仅当您发送具有已知类型的材质的实例时,此方法才有效。


0
投票

http://www.cplusplus.com/forum/beginner/236974/包含适当的解决方案。 make_shared应该是特定类型的;你可以毫无问题地将它存储在抽象类型的unique_ptr中。

© www.soinside.com 2019 - 2024. All rights reserved.