Буст опционально распознает наследование?
class Base {};
class Derived : public Base {};
void func(boost::optional<Base>&) {}
int main () {
boost::optional<Derived> x;
func(x);
}
Примет ли func оба варианта: базовый и производный?
2 ответа
Нет, это не сработает. func
принимает lvalue ссылку на boost::optional<Base>
, Это означает, что он может принимать lvalue типа boost::optional<Base>
lvalue типа, который происходит публично и однозначно из boost::optional<Base>
или какой-то другой тип, который имеет operator boost::optional<Base>&()
, Ничто из этого не относится к boost::optional<Derived>
, Шаблоны классов не ковариантны в системе типов C++ - boost::optional<Derived>
не наследуется от boost::optional<Base>
,
Это была бы другая история, если бы func
принял его аргумент по значению. Если бы это выглядело так:
void func(boost::optional<Base> ) { }
В этом случае вы можете позвонить func
с boost::optional<Derived>
, Но этот конвертирующий конструктор помечен explicit
так что вам придется написать:
func(boost::optional<Base>{x});
Хорошо, что это явно - вы отмечаете, что вы (потенциально) нарезаете x
,
Даже если это сработает (что, скорее всего, покупка, я не проверял), это приведет к нарезке. Только Base
часть будет храниться в необязательном порядке.
опционально содержит внутренний буфер размера, необходимого для хранения Base
, И даже если Base
будет того же размера, что и Derived
(как в вашем случае) все равно он будет хранить только Base
,
РЕДАКТИРОВАТЬ:
Выше был дан ответ на оригинальный вопрос, который содержал следующий код:
int main () {
boost::optional x(Derived());
func(x);
}
Такой код неверен по двум причинам:
boost::optional
требует аргумента шаблона- Даже с аргументом шаблона это все равно будет объявление функции.
Я проигнорировал эти проблемы и предположил, что нечто подобное подразумевалось:
int main () {
boost::optional<Base> x = Derived();
func(x);
}
Хотя этот код компилируется (по крайней мере, Visual Studio 2013 и Boost 1.60) и вызывает нарезку. Как видно, запустив следующую программу:
#include <boost/optional.hpp>
#include <iostream>
class Base
{
public:
virtual ~Base() { std::cout << "~Base" << std::endl; }
};
class Derived : public Base
{
public:
virtual ~Derived() { std::cout << "~Derived" << std::endl; }
};
int main()
{
boost::optional<Base> x = Derived();
}
который производит продукцию
~Derived ~Base ~Base
Второй ~Base
показывает, что optional
destroyes Base
объект, а не Derived
объект. (The ~Derived
от временного объекта Derived()
как первый ~Base
.)