3

可能重复:
派生**到基础**之间的转换

在主要使用 Python 的几年之后,我又回到了 C++,并且遇到了一堵强类型的墙。我认为我对基类和派生类的指针之间的基本多态性和类型转换有很好的处理(例如,派生类的指针可以类型转换为其基类的指针吗?),但这里有一个难点:为什么可以我不是将一个指向派生类的指针分配给一个指向它的基类的 p-to-p 的指针吗?

对于更多的上下文(也许还有关于减少pythonish的提示),这是我正在尝试做的简化版本。我想要一个指向对象的指针列表(从单个类派生)和一个标识它们的字符串(即 a map<string, obj*>)。然后,一组组件将传递标识字符串和位置的列表,以存储指向相应对象(即 a 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"] = &d_ptr;. 为什么?在 C++ 范式中,我应该做什么?我真的需要reinterpret_cast<base>()到处做丑陋的(不安全的?)吗?

4

7 回答 7

3

您正在丢失能够将 abase *转换为 a的必要信息derived *

考虑从多个基类继承的情况derived,因此强制转换需要调整指针值。然后derived *pd = static_cast<derived *>(pb)对于一个指向基地pb的指针将自动应用指针调整。

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

你应该做的是:

base *b_ptr;
... // existing code
derived *d_ptr = static_cast<derived *>(b_ptr);
于 2012-07-11T14:28:49.410 回答
2

考虑如果允许将 aderived**视为 a将启用什么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;
}
于 2012-07-11T14:57:32.433 回答
1

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

你应该能够用 astatic_cast而不是reinterpret_cast虽然解决这个问题:

ptr_dict["d"] = &static_cast<base*&>(d_ptr);
于 2012-07-11T14:32:30.107 回答
0

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

于 2012-07-11T14:25:29.707 回答
0

更换会简单很多

derived* d_ptr;

base* d_ptr;

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

于 2012-07-11T14:47:15.240 回答
0

您不能也不应该将 a 分配给 a 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().

不幸的是,我不确定要完成什么,所以我无法提供替代解决方案。

于 2012-07-11T15:14:18.317 回答
0

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

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

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

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

于 2012-07-11T15:03:52.713 回答