boost可选识别继承?

时间:2016-05-18 14:09:13

标签: c++ boost boost-optional

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

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

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

将func接受两个选项:base和derived?

2 个答案:

答案 0 :(得分:4)

不,它不会起作用。 funcboost::optional<Base>采用左值引用。这意味着它可以接受boost::optional<Base>类型的左值,这是一种从boost::optional<Base>公开且明确地派生的类型的左值,或者是具有operator boost::optional<Base>&()的其他类型的左值。 boost::optional<Derived>中没有一个是真的。类模板在C ++类型系统中不是coavrant - boost::optional<Derived>不从boost::optional<Base>继承。

如果func按价值采用其论证,那将是另一回事。如果它看起来像:

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

在这种情况下,您可以使用func来呼叫boost::optional<Derived>。但是转换构造函数标记为explicit,因此您必须编写:

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

这很明确 - 你明确表示你(可能)切片x

答案 1 :(得分:-1)

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

optional在内部保留一个存储Base所需大小的缓冲区。即使Base的大小与Derived相同(在您的情况下),它仍会仅存储Base

修改

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

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

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

  1. boost::optional需要模板参数
  2. 即使使用模板参数,它仍然是函数声明。
  3. 我忽略了这些问题,并认为这样的意思是:

    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会破坏Base个对象而不是Derived个对象。 (~Derived来自临时对象Derived(),与第一个~Base一样。)