Получение полученного класса из unique_ptr абстрактного базового типа - PullRequest
0 голосов
/ 09 июня 2018

У меня есть случай, когда я хочу предоставить чистый API для структур пространственного поиска.Теперь мне удобно представить больший случай в этом игрушечном примере.Здесь есть два абстрактных базовых класса ToySmall и ToyBig, экземпляр производного типа 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<ToySmall> для возврата ко-вариантного типа, потому что каждый производный тип 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 и использовать его.

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

С помощью:

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();
0 голосов
/ 09 июня 2018

Ваш код больше похож на 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...