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

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

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

func 会接受两个选项:基础和派生吗?

4

2 回答 2

4

不,这行不通。func接受对 的左值引用boost::optional<Base>。这意味着它可以接受 typeboost::optional<Base>的左值、公开且明确地派生自 的类型的左值boost::optional<Base>,或具有operator boost::optional<Base>&(). 这些都不是真的boost::optional<Derived>。类模板在 C++ 类型系统中不是协变的 -boost::optional<Derived>不继承自boost::optional<Base>.


如果func按价值论点,那将是一个不同的故事。如果它看起来像:

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

在这种情况下,您可以使用. 但是那个转换构造函数被标记了,所以你必须写:funcboost::optional<Derived>explicit

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

这是明确的,这很好——你清楚地表明你正在(可能)切片x

于 2016-05-18T14:18:52.960 回答
-1

即使它会起作用(这可能是我没有检查过的),它也会导致切片。只有Base部分存储在可选中。

optional 在内部保留存储所需大小的缓冲区Base。即使与(如您的情况Base一样)大小相同,Derived它也只会存储Base.


编辑:

以上答案是针对包含以下代码的原始问题给出的:

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

由于两个原因,此类代码不正确:

  1. boost::optional需要模板参数
  2. 即使使用模板参数,它仍然是函数声明。

我忽略了这些问题,并假设这样的事情是这样的:

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

产生输出

~派生
~基地
~基地

第二个~Base表明optional破坏Base对象而不是Derived对象。(与第一个一样~Derived来自临时对象。)Derived()~Base

于 2016-05-18T14:17:09.427 回答