【问题标题】:c++ store a reference to a pure virtual class as member of classc ++存储对纯虚拟类的引用作为类的成员
【发布时间】:2015-03-19 11:17:03
【问题描述】:

我有一个模板化包装器,其中包含一个类的实例,该类继承了一个纯虚拟类。
我的问题是如何将数据存储在包装器中。
- 我无法使用副本,因为无法实例化纯虚拟类(如果我使用简单的虚拟类,则无法进行切片)。
- 我没有设法保留参考。这个 ref 变得无效,因为我不管理我得到的对象的分配(超出范围)。
- 我唯一的解决方案是使用指针,即使我想避免这种情况,因为这不是很安全,我需要我的代码是健壮的。
我能做什么?

这是一个模拟我的问题的小例子:

#include <iostream>
#include <string>
#include <ctime>
#include <cmath>

using namespace std;

class Module
{
public:
    Module() : m(rand())
    {
        cout << "m = " << m << endl;
    }

    virtual void f() = 0;

    int m;
};

class ModuleA : public Module
{
public:
    ModuleA() : ma(rand())
    {
        cout << "ma = " << ma << endl;
    }

    void f() {}

    int ma;
};

template<typename T>
class Container
{
public:
    Container(T e) : element(e) {}

    T element;
};

// Objects are created outside of main
ModuleA createModule()
{
    return ModuleA();
}

Container<Module&> createContainer()
{
    return Container<Module&>(createModule());
}

int main()
{
    srand((unsigned int)time(NULL));

    Container<Module&> conta = createContainer();

    ModuleA& ca1 = dynamic_cast<ModuleA&>(conta.element); // wrong !

    system("pause");

    return 0;
}

【问题讨论】:

  • @AntoineLafarge 我在您的代码中没有看到任何Module&amp;。我看到的唯一参考是T&amp; Container&lt;T&gt;::element,我看到的唯一实例是Container&lt;ModuleA&gt;。只需将T&amp; element 替换为T element 即可。
  • 在我看来这是一个所有权问题;我过去在 C++ 中也遇到过一些问题。将 unique_ptr 用于内部所有权,仅将原始指针从它分发到您拥有的其他事物(封装实体)。将 shared_ptr 用于返回给调用者的东西,但返回给他们一个weak_ptr,合同是“如果我返回一个weak_ptr,在任何情况下你都不会用它构造一个shared_ptr并存储它——我负责这个对象”。这些是我多年来学到的一些东西。
  • 提高警告级别:warning C4239: nonstandard extension used : 'argument' : conversion from 'ModuleA' to 'ModuleA &amp;'
  • @GiulioFranco 我的错,我刚刚更新了代码以显示我想要做什么。
  • @AntoineLafarge 我强烈建议你也看看std::weak_ptr

标签: c++ reference wrapper pure-virtual template-classes


【解决方案1】:

您可以在容器中使用std::shared_ptr,即

template<typename T>
class Container
{
public:
    // The pointer you get must be managed as well
    Container(std::shared_ptr<T> e) : element(e) {}

    std::shared_ptr<T> element;
};

那将是完全安全的。事实上,如果对象在创建它的代码中超出范围,您仍然有一个有效的指针,直到容器自身超出范围。如果std::shared_ptr 的语义不完全适合您的情况,您可以使用std::weak_ptrstd::unique_ptr 进一步调整内存所有权关系。

您绝对应该查看std::weak_ptr,因为它允许您禁止某些代码获取指针的所有权,但仍然允许访问 如果指针在您需要的位置有效访问它。它还可以防止内存保留循环,因为 std::weak_ptr 不拥有内存。

【讨论】:

  • @GiulioFranco OP 声明“这个 ref 变得无效,因为我不管理我得到的对象的分配(超出范围)。”所以我相当假设包装器不应该是唯一的所有者。如果容器超出范围,那将不会很漂亮,但该对象仍然通过例如其他地方引用。一个原始指针。
  • 我会将元素设为私有并创建一个返回weak_ptr的公共成员函数。我不会从 unique_ptr 返回原始指针。
  • @Robinson 那么这取决于 OP 真正需要什么。还是同意最后一句话。
  • 我会推荐 shared_ptr,从公共方法返回一个 weak_ptr。仅返回weak_ptr 的另一个原因是,它有助于避免可能导致对象保持活动状态的循环,即使您认为它们已被破坏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 2015-05-27
  • 2011-03-31
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2014-08-14
相关资源
最近更新 更多