【问题标题】:I can't assign from pointer to pointer to derived class and pointer to pointer to base class? [duplicate]我不能从指向派生类的指针和指向基类的指针分配指针? [复制]
【发布时间】:2012-07-11 14:20:46
【问题描述】:

可能重复:
Conversion between Derived** to Base**

在使用了几年的 Python 之后,我又回到了 C++,并且遇到了强类型的墙。我认为我对基类和派生类的指针之间的基本多态性和类型转换(例如Can a pointer of a derived class be type cast to the pointer of its base class?)有很好的处理,但这里有一个障碍:为什么我不能将指向派生类的指针分配给p-to-p 到它的基类?

有关更多上下文(也许还有关于减少 Python 化的提示),这是我正在尝试做的简化版本。我想要一个指向对象的指针列表(从单个类派生)和一个标识它们的字符串(即map<string, obj*>)。然后,一组组件将传递一个标识字符串和位置的列表,以存储指向相应对象的指针(即map<string, obj**>)。然后我应该能够通过其字符串 id 找到适当的对象,并填写适当的指针以供组件后续使用。 执行此操作的简化代码是

#include <map>
#include <string>
using namespace std;

class base
{
};

class derived: public base
{

};

typedef map<string, base**> BasePtrDict;
typedef map<string, base*> BaseDict;


int main(int argc, char* argv[])
{
    base b1, b2;
    derived d;
    derived* d_ptr;

    BaseDict base_dict;
    base_dict["b1"] = &b1;
    base_dict.insert(make_pair("b2",&b2)); // alternate syntax
    base_dict["d"]= &d;

    BasePtrDict ptr_dict;
    ptr_dict["d"] = &d_ptr;

    for (auto b = ptr_dict.begin(); b != ptr_dict.end(); b++)
        *(b->second) = base_dict[b->first];

    return 0;
}

这会在ptr_dict["d"] = &amp;d_ptr; 处遇到编译错误。为什么?在 C++ 范式中,我应该做什么?我真的需要到处做丑陋的(不安全的?)reinterpret_cast&lt;base&gt;()吗?

【问题讨论】:

  • 感谢大家提供有用的参考资料和示例。现在绝对是有道理的,我将不得不考虑如何优雅地做到这一点,同时保持强类型 ala C++。

标签: c++ pointers polymorphism


【解决方案1】:

您丢失了将base * 转换为derived * 的必要信息。

考虑derived 继承自多个基类的情况,因此强制转换需要调整指针值。然后derived *pd = static_cast&lt;derived *&gt;(pb) 用于指向基址的pb 将自动应用指针调整。

但是derived *pd; base **ppb = &amp;pd; *ppb = *pb 将无法应用指针调整,因此这是不合法的。

你应该做的是:

base *b_ptr;
... // existing code
derived *d_ptr = static_cast<derived *>(b_ptr);

【讨论】:

    【解决方案2】:

    考虑如果允许将derived** 视为base** 会启用什么:

    class base
    {
    };
    
    class derived: public base
    {
    public:
        int boom;
    }
    
    
    void light_the_fuse( base** pb)
    {
        *pb = new base;
    }
    
    
    int main()
    {
        derived* pd = NULL;
    
        light_the_fuse( &pd);
    
        pd->boom = 42;  // uh oh, `pd` points to a `class base`...
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      为了进行子到基的转换,需要关联类型。对于derived**base**,这意味着derived*base* 的子代,这显然是不正确的,因为它们是正交指针类型(恰好指向相关类)。

      您应该可以使用static_cast 而不是reinterpret_cast 来解决这个问题:

      ptr_dict["d"] = &static_cast<base*&>(d_ptr);
      

      【讨论】:

        【解决方案4】:

        直接将derived* 转换为base* 是可以的,但这不是您要尝试的。您正在尝试将derived** 转换为base**,这不是隐式转换。除此之外,我可以问为什么吗?我什至会继续问你是否真的需要指针,而是双指针?

        【讨论】:

          【解决方案5】:

          替换起来会简单很多

          derived* d_ptr;
          

          base* d_ptr;
          

          并在您可能需要应用 d_ptr 的确切类型时随时使用强制转换,但当然面向对象的原则表明这种情况应该非常罕见。

          【讨论】:

            【解决方案6】:

            您不能也不应该将Derived** 分配给Base**,因为它不安全。如果允许强制转换,那么它将允许Derived* 指向不是Dervied 类型的类型。考虑以下几点:

            class Base {};
            class Derived: public Base {};
            class Other: public Base {};
            
            ...
            
            Derived derived;
            Derived* derived_p   = &derived;   // derived_p points to derived.
            Derived** derived_pp = &derived_p; // derived_p points to derived.
                                               // derived_pp points to derived_p.
            Base** base_pp = derived_pp;       // derived_p points to derived.
                                               // base_pp points to derived_p.
            
            Other other;
            Other* other_p = &other;           // other_p points to other.
            
            *bpp = op;                         // base_pp points to derived_p.
                                               // derived_p points to other.
            

            如果上述代码有效,则允许Derived* derived = new Other()

            很遗憾,我不确定要完成什么,所以我无法提供替代解决方案。

            【讨论】:

              【解决方案7】:

              这几乎类似于Why do I need a reinterpret_cast to convert Fred ** const to void ** const?

              指向两种不同对象类型的指针基本上是不兼容的。但是,也有例外

              • Derived*Base*... Derived 和 Base 相关,因此允许转换(在类型转换为 Base* 之后,指针实际上将指向 Base 类型的对象
              • T*void* - 允许(参见上面的链接)

              但没有理由让D** 被允许转换为B**,因为B*D* 本质上是不同的类型。

              【讨论】:

                猜你喜欢
                • 2016-02-19
                • 1970-01-01
                • 1970-01-01
                • 2022-01-03
                • 1970-01-01
                • 2013-03-04
                • 2021-09-09
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多