2012-07-11 138 views
3

可能重复:
Conversion between Derived** to Base**我不能从指针指向派生类的指针和指向基类的指针吗?

我收到回C++经过几年大多的Python,和我打起来反对强类型的墙。我认为我有基本的多态性和基类派生类指针之间的类型转换(例如Can a pointer of a derived class be type cast to the pointer of its base class?),但是这里有一个stumper:为什么我不能指派一个指向派生类的指针指向p- to-p到它的基类?

欲了解更多的上下文(也许提示做这个更少pythonishly),这是我试图做的简化版本。我想要一个指向对象的指针列表(从单个类派生)和一个标识它们的字符串(即一个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"] = &d_ptr;运行到一个编译错误。为什么?在C++范例中,我该怎么做?我真的需要做到丑陋(不安全?)reinterpret_cast<base>()无处不在吗?

+0

谢谢所有有用的参考和示例。现在肯定有意义,我不得不考虑如何在保持强大的打字ala C++的同时优雅地做到这一点。 – Bismark 2012-07-12 09:00:57

回答

0

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

3

您正在失去必要的信息,以便能够将base *投射到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); 
1

为了做一个孩子到基转换的类型都需要进行相关。对于derived**base**这意味着derived*base*的孩子,这显然不是真实的,因为它们是正交指针类型(碰巧指向相关类)。

你应该能够用static_cast,而不是reinterpret_cast虽然解决了这个:

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

不是'dynamic_cast'? – 2012-07-11 14:38:56

0

这将是更简单的更换

derived* d_ptr; 

base* d_ptr; 

和使用随时可能需要应用d_ptr的确切类型,但当然是th面向对象原则认为这种情况应该是非常罕见的。

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; 
} 
0

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

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

  • Derived*Base* ...派生和基础是相关的,因此,转换允许(值映射为Base*后,指针实际上是指向Base类型的对象
  • T*void* - 允许(见上面的链接)

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

0

您不能也不应该将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()

不幸的是,我不完全确定试图完成什么,所以我不能提供替代解决方案。