抽象类和唯一指针

时间:2017-06-07 13:03:49

标签: c++ inheritance constructor c++14 abstract-class

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

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

4 个答案:

答案 0 :(得分:12)

这个电话:

security.protocol=SASL_PLAINTEXT (or SASL_SSL)
sasl.mechanism=GSSAPI
sasl.kerberos.service.name=kafka

尝试创建类std::make_unique<Material>(mat1) 的实例,与Material类型无关。您似乎需要在班级中使用方法mat1

clone()

然后class Material { ... virtual std::unique_ptr<Material> clone() const = 0; }; ctor将是:

Mix

并且您需要在每个派生类中实现Mix(const Material& mat1, const Material& mat2) : mat1_(mat1.clone()) , mat2_(mat2.clone()) {}

clone()

答案 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 :(得分: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';
}

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

答案 3 :(得分:0)

http://www.cplusplus.com/forum/beginner/236974/包含正确的解决方案。 make_shared应该是特定类型;然后,您可以毫无问题地将其存储在抽象类型的unique_ptr中。