mkmostafa
mkmostafa

Reputation: 3171

boost optional recognizes inheritance?

class Base {};
class Derived : public Base {};

void func(boost::optional<Base>&) {}

int main () {
  boost::optional<Derived> x;
  func(x);
}

will func accept both optionals: base and derived?

Upvotes: 4

Views: 867

Answers (2)

Adam Badura
Adam Badura

Reputation: 5339

Even if it would work (which is likely buy I haven't checked) it would cause slicing. Only Base part would be stored in optional.

optional keeps internally a buffer of the size needed to store Base. And even if Base would be of the same size as Derived (as in your case) still it would store only Base.


EDIT:

Above answer was given for the original question which contained following code:

int main () {
  boost::optional x(Derived());
  func(x);
}

Such code is not correct because of two reasons:

  1. boost::optional requires template argument
  2. Even with the template argument it would still be function declaration.

I have ignored those issues and assumed that something like this was meant:

int main () {
  boost::optional<Base> x = Derived();
  func(x);
}

While that code does compile (at least Visual Studio 2013 and Boost 1.60) and causes slicing. As can be seen by running following program:

#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();
}

which produces output

~Derived
~Base
~Base

The second ~Base shows that optional destroyes Base object rather than Derived object. (The ~Derived is from the temporary object Derived() as is the first ~Base.)

Upvotes: -1

Barry
Barry

Reputation: 303526

No, it won't work. func takes an lvalue reference to boost::optional<Base>. That means it can accept an lvalue of type boost::optional<Base>, an lvalue of a type that derives publicly and unambiguously from boost::optional<Base>, or some other type that has an operator boost::optional<Base>&(). None of those is true of boost::optional<Derived>. Class templates are not coviarant in the C++ type system - boost::optional<Derived> does not inherit from boost::optional<Base>.


It would be a different story if func took its argument by value. If it looked like:

void func(boost::optional<Base> ) { }

In that case, you could call func with a boost::optional<Derived>. But that converting constructor is marked explicit, so you would have to write:

func(boost::optional<Base>{x});

It's good that this is explicit - you are marking clear that you are (potentially) slicing x.

Upvotes: 4

Related Questions