функция виртуального класса c ++, возвращающая экземпляр конкретного подкласса - PullRequest
3 голосов
/ 07 октября 2019

Что бы я хотел, если бы не с этим синтаксисом, а по духу:

class A
{
   virtual A f()=0;
};

class B : public A
{
   B f();
};

Я вижу проблему с кодом выше: A является виртуальным, поэтому ни один экземпляр A не может быть создан,следовательно, ни один экземпляр A не может быть возвращен.

Тем не менее, конкретные подклассы A (например, B) должны будут реализовать функцию f, которая всегда сможет вернуть экземпляр себя (например, экземпляр B)то есть экземпляр подкласса A.

Хотя вышеприведенное неверно и не компилируется, есть ли способ получить что-то подобное действительным? Возможно, но не обязательно, например:

class A 
{
   virtual "a concrete sublclass of A" f()=0;
};

примечание: я предпочитаю не возвращать указатель или ссылку, так как я бы предпочел, чтобы B не управлял своим экземпляром как атрибутом.

примечание: если возможно, c ++ 11, но любопытно также узнать о более новых версиях

Ответы [ 4 ]

4 голосов
/ 07 октября 2019

Ваше решение рискует нарезать объект. Копирование B как A, вероятно, не будет работать так, как вы ожидаете. Вообще, лучше избегать семантики значений при работе с полиморфными типами. Попробуйте вместо этого вернуть std::unique_ptr<A>:

#include <memory>
class A
{
public:
   virtual std::unique_ptr<A> f()=0;
};

class B : public A
{
public:
   std::unique_ptr<A> f() override;
};

Для этого требуется C ++ 11. Он будет вести себя так, как вы ожидаете, и пользователю не придется управлять временем жизни полученного объекта.

Однако, в отличие от того, что было показано в исходном коде, B::foo() не даст вам доступана полный интерфейс B. Мне не ясно, требуется ли это или нет. Если это так, вам понадобится дополнительный слой. Например, определите g(), который возвращает std::unique_ptr<B>, который f() вызывает:

class B : public A
{
public:
   std::unique_ptr<A> f() override { return g(); }
   std::unique_ptr<B> g();
};
2 голосов
/ 07 октября 2019

Похоже, вы пытаетесь написать какую-то фабричную или клонирующую функцию. Обычно это делается с помощью std::unique_ptr, чтобы передать право владения созданным объектом вызывающей стороне:

class A
{
   virtual std::unique_ptr<A> f() = 0;
};

class B : public A
{
   std::unique_ptr<A> f() override;
};

Демо

Единственным недостатком является то, что вы не можете иметьB::f возвращает std::unique_ptr<B>, поскольку оно не ковариантно с std::unique_ptr<A> (даже если оно неявно преобразуется в него).

1 голос
/ 07 октября 2019

примечание: если возможно c ++ 11, но любопытно также узнать о более новых версиях

Нет. это невозможно. Вы можете вернуть ковариантный тип в производный класс.

Если тип возвращаемого значения в базовом классе равен A&, то можно вернуть B& в B.
Если возвращаемый результатвведите в базовом классе A*, можно вернуть B* в B.

class A
{
   virtual A& f()=0;
   virtual A* g()=0;
};

class B : public A
{
   B& f();
   B* g()=0;
};
0 голосов
/ 07 октября 2019

Напишите что-то вроде

class A
{
   virtual const A& f() const = 0;
};

class B : public A
{
   const B& f() const override { return *this; }
};

Вместо ссылки вы можете использовать указатели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...