【问题标题】:How to cast to privately derived child type?如何转换为私有派生的子类型?
【发布时间】:2016-07-31 08:14:50
【问题描述】:

以下是实现共享指针的尝试,修改后的语义为operator==

template <typename T>
struct deref_shared_ptr: private std::shared_ptr<T> {
    using Base = std::shared_ptr<T>;
    // ... using statements to include functionality from the base.

    bool operator==(const deref_shared_ptr rhs) const {
        return (**this == *rhs);
    }
};

我正在努力为这种类型实现等效的std::make_shared。这是我的尝试:

template< class T, class... Args >
deref_shared_ptr<T> make_deref_shared( Args&&... args ) {
    return reinterpret_cast<deref_shared_ptr<T>>(std::make_shared<T>(args...));
}

这不起作用:编译器 (g++ 5.4.0) 抱怨无效转换。为什么它不起作用,我应该怎么做而不是这个演员?

【问题讨论】:

  • 使用friend。这不是罪。
  • @n.m.您的意思是有一个带有std::shared_ptr 参数的私有构造函数吗?
  • 抱歉,没有仔细看你的代码。仅当派生类型具有采用父类型的构造函数,或者父类型具有正确的类型转换运算符时,才能强制转换为派生类型(不是指针)。所以是的,你确实需要一个构造函数。是否将其设为私有取决于您,
  • @n.m.这使得下面的答案错了,不是吗?
  • 看起来是的,是的。

标签: c++ inheritance private-inheritance


【解决方案1】:

您会看到此编译器错误消息,因为 reinterpret_cast 无法通过私有继承进行强制转换。请查看该主题的以下主题:difference between c++ castsconversion which may be handled by c-style cast only

通过private 继承的唯一方法是c 样式转换。因此,如下更改您的示例会使您的示例工作:

template< class T, class... Args >
deref_shared_ptr<T> make_deref_shared(Args&&... args) {
    return (deref_shared_ptr<T>)(std::make_shared<T>(args...));
}

c 样式转换在一般情况下是不安全的,因为它在多重继承和其他一些情况下可能无法正常工作,但 AFAIK 在这种情况下是安全的。

【讨论】:

  • 在这种情况下,答案是否会反过来(即从孩子转换到基地)?我认为我将需要该演员表来实现新类型的构造函数。
  • 是的,应该是。 c++ cast没有关于私有继承的信息
  • 解决方案不起作用。编译器抱怨缺少带有 std::shared_ptr 参数的构造函数,我显然不想提供。
  • @AlwaysLearning 您正在将指向基础对象的指针转换为指向派生对象的指针,而在任何地方都看不到派生对象。然后您继续取消引用结果指针。是什么让您认为这可能被定义?
  • @AlwaysLearning “我的派生类型的布局与基本类型完全相同。”即使这是真的,它也不会为规则创建例外。 “res 是派生对象”是一种流行的误解,在现实中没有任何根据。见stackoverflow.com/questions/20518237/…
【解决方案2】:

我建议您的deref_shared_ptr 实现一个接收std::shared_ptr 作为参数的构造函数,这样就可以进行转换。现在你的编译器不知道如何从std::shared_ptr 生成deref_shared_ptr。这正是我们将教你的编译器做的事情。

我注意到您添加了自定义 operator== 以正确比较您的类型与 std::shared_ptr。在这里,我们想做同样的事情,但使用构造函数。我们需要一个构造函数,该构造函数可以使用 std::shared_ptr! 正确构造您的类型!

构造函数如下所示:

template<typename T>
struct deref_shared_ptr : private std::shared_ptr<T> {
    // An alias to the parent may help msvc with templated parent types
    using parent = std::shared_ptr<T>; 

    // Implement a constructor that takes shared_ptr by copy and move
    deref_shared_ptr(const parent& ptr) : parent{ptr} {}
    deref_shared_ptr(parent&& ptr) : parent{std::move(ptr)} {}

    // stuff...
};

然后,make 函数的实现就变得微不足道了:

template<typename T, typename... Args>
deref_shared_ptr<T> make_deref_shared(Args&&... args) {
    // Don't forget perfect forwarding here!
    return std::make_shared<T>(std::forward<Args>(args)...);
}

编辑:

或者,如果你的构造函数没有做任何操作,你可以利用继承构造函数:

template<typename T>
struct deref_shared_ptr : private std::shared_ptr<T> {
    using parent = std::shared_ptr<T>; 

    // Implement constructors
    using parent::parent;

    // stuff...
};

这将简化构造函数的实现,并使您的类型通过构造与 std::shared_ptr 兼容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-01
    • 2022-10-14
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多