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

Saving abstract value object in wrapper and Usage of inheritance

本文关键字:继承 用法 包装 抽象 对象 保存 存在      更新时间:2023-10-16

我有有关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的字节,而不是IFoo实现的字节。也许我可以使用值IFoo foo来调用派生的虚拟方法?

感谢任何回复

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

不幸的是,一旦涉及多态性,是的,不是,没有。但是,如果您使用智能指针:

,您可以获得存储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>中时(。

通常,当我们想更改类的接口或想要实现其他功能时,我们会创建包装器 std::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)) ;
}

此功能将适用于Foo1Foo2等所有类型,并且不需要包装器。