【问题标题】:Getting a Derieved class from the unique_ptr of abstract Base Type从抽象基类型的 unique_ptr 中获取派生类
【发布时间】:2018-11-19 02:10:58
【问题描述】:

我有一个案例,我想为空间搜索结构公开一个干净的 API。 现在,我很方便地在这个玩具示例中代表了更大的情况。 这里有两个抽象基类ToySmallToyBig,派生类型ToySmall的实例是在returnSmall方法中创建的ToyBig的实例派生类型。

以下是ToyInterface.h的内容

#include <iostream>
#include <memory>

class ToySmall
{
public:
   ToySmall() {}
   virtual void toyMethod() const = 0;
};

class ToyBig
{
public:
   ToyBig() {}
   virtual std::unique_ptr<ToySmall> returnSmall() = 0;
};

我将returnSmall 的返回类型设为std::unique_ptr&lt;ToySmall&gt;,以便返回协变类型,因为ToyBig 的每个派生类型都返回不同的ToySmall 派生类型。

但是在实现这些接口并按照我的意图使用它们时,我在获取ToySmallImpl 的具体实例时遇到了问题,如下面的文件中所示。我在下面的源代码中包含了错误。

#include <iostream>
#include "ToyInterfaces.h"

class ToySmallImpl : public ToySmall
{
public:
  ToySmallImpl()
  : ToySmall()
  {}

  void toyMethod() const override
  {
    std::cout << "All Good!!" << std::endl;
  }
};

class ToyBigImpl : public ToyBig
{
public:
  ToyBigImpl()
  : ToyBig()
  {}

  std::unique_ptr<ToySmall> returnSmall() override
  {
    ToySmall* small;
    ToySmallImpl smallImpl;
    small = &smallImpl;
    return std::unique_ptr<ToySmall>(small);
  }
};

int main()
{
  ToyBigImpl bigImpl;
  std::unique_ptr<ToySmall> toySmall =  bigImpl.returnSmall();

  // ToySmallImpl toySmallImpl = *toySmall;
  // Error : error: conversion from ‘ToySmall’ to non-scalar type ‘ToySmallImpl’ requested

  ToySmallImpl toySmallImpl = static_cast<ToySmallImpl>(*toySmall);
  // Error : no matching function for call to ‘ToySmallImpl::ToySmallImpl(ToySmall&)’

  toySmallImpl.toyMethod();
}

由于Impl 类是从我拥有的接口扩展而来的,并且也可以由其他开发人员实现,我不想像大多数其他解决方案那样拥有复制构​​造函数或= 运算符.如果它只是为了我,我会非常高兴地让它工作,但我可以。但是,我希望它是干净的,以便我可以将解决方案作为指南提供给 API 的其他用户。

我想知道是否有其他人有类似的情况,可以指出一个可能的解决方案,在 main 中,我将能够创建 ToySmallImpl 的实例并使用它。

【问题讨论】:

  • 您的returnSmall() 正在返回本地对象的地址,尽管它包含在std::unique_ptr 中。这意味着调用者会收到一个指向不再存在的对象的指针 - 因此调用者对该对象的任何使用都会产生未定义的行为。当返回的unique_ptr 超出范围时,这也意味着未定义的行为,因为它试图释放不再存在的对象。

标签: c++ c++11 inheritance design-patterns


【解决方案1】:

与:

std::unique_ptr<ToySmall> returnSmall() override
{
    ToySmall* small;
    ToySmallImpl smallImpl;
    small = &smallImpl;
    return std::unique_ptr<ToySmall>(small); // Return dangling pointer
}

你返回悬空指针,你可以这样做:

std::unique_ptr<ToySmall> returnSmall() override
{
    return std::make_unique<ToySmallImpl>();
}

那么,对于多态类型,“正确的”转换是dynamis_cast

std::unique_ptr<ToySmall> toySmall =  bigImpl.returnSmall();

auto& toySmallImpl = dynamic_cast<ToySmallImpl&>(*toySmall);
toySmallImpl.toyMethod();

【讨论】:

  • 这适用于玩具示例,但我使用 c++11 构建搜索结构,其中 make_unique 不可用,您对如何处理这种情况有任何建议吗?
  • 实现make_unique: template &lt;typename T, typename ...Ts&gt; std::unique_ptr&lt;T&gt; make_unique(Ts&amp;&amp;...args) { return std::unique_ptr&lt;T&gt;(new T(std::forward&lt;Ts&gt;(args)...)) }.
【解决方案2】:

您的代码更像Proxy Design Pattern. 试试这个:

class ToyBigImpl : public ToyBig
{
public:
    ToyBigImpl()
        : ToyBig()
    {}

    std::unique_ptr<ToySmall> returnSmall() override
    {
        std::unique_ptr<ToySmall> small = std::make_unique<ToySmallImpl>();
        return std::move(small);
    }
};

int main(int argc, char** argv)
{
    ToyBigImpl bigImpl;
    std::unique_ptr<ToySmall> toySmall = bigImpl.returnSmall();

    ToySmallImpl toySmallImpl = *(reinterpret_cast<ToySmallImpl*>(toySmall.get()));

    toySmallImpl.toyMethod();                                                                         
    return 0;
}

【讨论】:

    猜你喜欢
    • 2011-01-11
    • 2022-01-24
    • 2015-03-30
    • 2010-11-01
    • 2013-06-30
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多