经过几年的大部分Python之后,我又回到了C ++,并且正在打击一个强类型的墙。我认为我对基本多态和基类和派生类的指针之间的类型转换有很好的处理(例如Can a pointer of a derived class be type cast to the pointer of its base class?),但这里有一个难题:为什么我不能指定一个指向派生类的指针到p-to-p到它的基类?
对于更多上下文(以及可能不那么诡异的提示),这里是我正在尝试做的简化版本。我想要一个指向对象的指针列表(从单个类派生)和一个标识它们的字符串(即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 :(得分: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 :(得分: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;
}
答案 2 :(得分:1)
为了进行从子到基的转换,需要将类型相关联。对于derived**
到base**
,这意味着derived*
是base*
的子项,显然不是真的,因为它们是正交指针类型(碰巧指向相关类)
你应该能够用static_cast
而不是reinterpret_cast
来解决这个问题:
ptr_dict["d"] = &static_cast<base*&>(d_ptr);
答案 3 :(得分:0)
直接投射derived*
到base*
是可以的,但这不是你正在尝试的。您正在尝试derived**
到base**
,这不是隐式演员。除此之外,我可以问为什么?我甚至会问你是否真的需要指针,但需要双指针?
答案 4 :(得分:0)
替换
会简单得多derived* d_ptr;
带
base* d_ptr;
并且当你可能需要应用精确类型的d_ptr时随时使用强制转换,但当然,面向对象的原则说这种情况应该非常罕见。
答案 5 :(得分:0)
这与Why do I need a reinterpret_cast to convert Fred ** const to void ** const?
几乎相似指向两种不同对象类型的指针基本上是不兼容的。但是,也有例外
Derived*
到Base*
... Derived和Base是相关的,因此允许转换(在转换为Base*
之后,指针实际上指向{{1}的对象1}}输入Base
至T*
- 允许(请参阅上面的链接)但没有理由允许void*
转换为D**
,因为B**
和B*
本质上是不同的类型。
答案 6 :(得分: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()
。
不幸的是,我不确定要完成什么,所以我无法提供替代解决方案。