在包装器中保存抽象值对象和继承的使用

时间:2019-07-02 15:10:00

标签: c++ c++11

我对C ++类继承有疑问。 我有一个具有虚拟方法的类,例如:

class IFoo {
public:
    virtual int sayFoo() = 0;
};

我有几种实现,例如:

class Foo1: public IFoo {
public:
    virtual int sayFoo() {
        return 1;
    }
};

class Foo2: public IFoo {
public:
    virtual int sayFoo() {
        return 2;
    }
};

我想将IFoo实例保存在一个虚拟容器类(如某种包装器)中,以暴露与IFoo相同的接口:

class DummyWrapper : public IFoo {
public:
    DummyWrapper(IFoo& foo): foo{foo} {}
    virtual int sayFoo() {
        return foo.sayFoo(); //ALPHA
    }
private:
    IFoo& foo; //BETA
};

通常,一切都会正常运行,例如:

IFoo& foo = Foo1{};
DummyWrapper wrapper{foo};

wrapper.sayFoo();

我的问题是foo实际上只是一个r值,它的作用域消失后就将其删除,例如:

DummyWrapper generateWrapper() {
    return DummyWrapper{Foo1{}};
}

这导致“ ALPHA”行中出现读取问题。 一种解决方案是将r值放在堆上,并使用指针访问foo。由于我是C ++的新手,可能会遇到XY问题,所以我的问题是:

  • 这是唯一的解决方案吗?有没有更好的方法来解决问题?
  • 我认为我无法用IFoo foo替换“ BETA”行,因为这样DummyWrapper将始终存储IFoo而不是{{1 }}实现。还是我可以使用值IFoo来调用派生的虚方法?

感谢您的任何回复

2 个答案:

答案 0 :(得分:4)

  

这是唯一的解决方案吗?有没有更好的方法来解决问题?

不幸的是,一旦涉及到多态性,是的,是的,不是的,没有的。但是,如果使用智能指针,则可以得到与存储IFoo foo几乎相同的解决方案:

// member:
std::unique_ptr<IFoo> foo;

// constructor:
DummyWrapper(std::unique_ptr<IFoo>&& foo): foo(std::move(foo)) { }
// need to accept r-value         ^
// reference: std::unique_ptr is only movable, not copiable!
// for the same reason, you need to preserve the r-value reference
// on assignment to member...

// creation of the wrapper:
return DummyWrapper(std::make_unique<Foo1>(/* arguments for constructor, if there are */));
  

我不认为我可以用IFoo foo替换“ BETA”行,因为这样DummyWrapper将始终存储IFoo的字节,而不是IFoo实现的字节。或者也许我可以使用IFoo foo值来调用派生的虚方法?

绝对正确:这是一种称为“对象切片”的效果,在这一点上,将派生对象分配给基本对象时,所有来自派生类型的多余东西都会丢失。相当普遍的问题(例如,当人们尝试将派生对象存储在std::vector<Base>中时)。

答案 1 :(得分:1)

通常,当我们想要更改类的接口或想要实现其他功能时,我们创建包装器,例如
Singaporestd::queue<T>上的包装器/适配器(默认情况下)
std::std::deque<T>类模板充当基础容器的包装器-仅提供一组特定的功能。队列将元素推入基础容器的背面,并从正面弹出它们。
在您的情况下,我认为您不需要std::queue<T>,可以使用DummyWrapper代替IFoo,它将完成相同的工作。

让我们考虑以下功能,

DummyWrapper

该功能将适用于所有类型,例如bool isEven( IFoo& ifoo) // Not const& because sayFoo() is not const method. { return ( 0 == ( ifoo.sayFoo() % 2)) ; } Foo1,并且不需要包装器。