интерфейс — у нас есть лучший способ вернуть абстрактные классы в C ++?

Я хочу начать добавлять некоторые интерфейсы в мой C ++-код, чтобы мне было проще проводить модульное тестирование с использованием макетов.

Проблема в том, что возвращать абстрактные классы из метода в C ++ очень трудно. Вы не можете вернуть по значению, поэтому вам нужно вернуть указатель или ссылку.

Учитывая все разработки в C ++ за последние шесть или семь лет, я подумал, что могу спросить, возможно, у нас есть лучший способ вернуть абстрактный базовый класс. Интерфейс без шума будет выглядеть примерно так, но я уверен, что это невозможно.

IBaseInterface getThing() {return DerivedThing{};}

Я помню, как делал это в прошлом, используя указатель (вероятно, умный указатель сейчас):

std::unique_ptr<IBaseInterface> getThing() {return std::make_unique<DerivedThing>();}

Проблема с указателем заключается в том, что я никогда не планирую использовать в своих интересах nullptr, поэтому издержки и шум при работе с указателем, а не со значением, не приносят мне пользы для читателя.

Есть ли лучший способ, которым я не знаю, чтобы справиться с этим?

4

Решение

РЕДАКТИРОВАТЬ: предоставляет полный пример, включая создание копируемой полиморфной ручки.

#include <iostream>
#include <utility>
#include <memory>

struct IBaseInterface {
IBaseInterface() = default;
IBaseInterface(IBaseInterface const&) = default;
IBaseInterface(IBaseInterface &&) = default;
IBaseInterface& operator=(IBaseInterface const&) = default;
IBaseInterface& operator=(IBaseInterface &&) = default;
virtual ~IBaseInterface() = default;

virtual std::unique_ptr<IBaseInterface> clone() const = 0;
virtual void do_thing() = 0;
};

struct handle
{
handle(std::unique_ptr<IBaseInterface> ptr)
: _impl(std::move(ptr))
{}

handle(handle const& r)
: _impl(r._impl->clone())
{}

handle(handle && r)
: _impl(std::move(r._impl))
{}

handle& operator=(handle const& r)
{
auto tmp = r;
std::swap(_impl, tmp._impl);
return *this;
}

handle& operator=(handle && r)
{
_impl = std::move(r._impl);
return *this;
}// interface here
void do_thing() { _impl->do_thing(); }

private:
std::unique_ptr<IBaseInterface> _impl;
};

struct DerivedThing : IBaseInterface
{
std::unique_ptr<IBaseInterface> clone() const override
{
return std::make_unique<DerivedThing>(*this);
}

void do_thing() override
{
std::cout << "I'm doing something" << std::endl;
}

};

handle make_thing()
{
return handle(std::make_unique<DerivedThing>());
};

int main()
{
auto a = make_thing();
auto b = a;

a.do_thing();
b.do_thing();

return 0;
}

Теперь используйте ваш дескриптор, как если бы он имел (перемещаемую) семантику значения

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]