将“派生**”分配给“基础**”时的C2440

时间:2014-04-28 16:49:16

标签: c++ casting

我们假设我有Base班和Derived班级:

class Base {};

class Derived : public Base {};

fun我现在可以明确地将Derived的指针指定给myBase的内容,如下所示:

void fun( Base** myBase ) {

    Derived* myDerived = new Derived();
    *myBase = myDerived;
}

int _tmain(int argc, _TCHAR* argv[])
{
    Base *myBase = NULL;
    fun( &myBase );

    return 0;
}

现在,问题是我要分配给Base*数组(我不能使用typedef来掩盖三星级,因为fun的签名是自动生成的):< / p>

void fun( Base*** myBase ) {

    Derived** myDerived = new Derived*();
    *myBase = myDerived;
}

为什么从C2440: '=' : cannot convert from 'Derived **' to 'Base **'Derived*的转换完全没问题,我会得到Base*

3 个答案:

答案 0 :(得分:5)

答案在于基础指针的强制转换实际上在C ++中的作用。请考虑以下简单示例:

struct A { std::uint32_t a; };
struct B { std::uint32_t b; };
struct D : A, B { std::uint32_t d; };

此处D有两个基础,AB。但是只有其中一个可以在D的开头生活(假设它是A),所以当您将D转换为另一个(B)时,指针的值需要更改,指向D 中间的某个点

要想象这一点,请考虑一下D类型的对象在你的记忆中的样子:

0 1 2 3 4 5 6 7 8 9 A B
[ A::a ][ B::b ][ D::d ]
^ a D* would point here
^ a A* would point here
        ^ a B* must point here

虽然D期望所有这三个整数,但在将此对象视为A时,我们只期望第一个,但指针(数字上)是相同的,我们只期望一个较短的物体。但是,在将其视为B时,我们需要指向中间的一个整数。

当你对一个指针执行此操作时,编译器将通过适当地更改指针的值来为您处理此问题。但是,当您对指针数组执行此操作时,编译器需要在其中的所有元素上发出循环并更正每个指针 - 实际上它甚至无法知道数组的结束位置(因为编译器只看到指针到它的开始)!

因此C ++不允许这种转换。

答案 1 :(得分:1)

指针转换规则按照标准

的规定进行管理

N3337:4.10指针转换[conv.ptr]

如果您在examaple中描述了从指向派生的指针转换为指向基础的指针

Derived* myDerived = new Derived();
*myBase = myDerived;

是有效的,因为标准说

  

类型为“指向cv D的指针”的prvalue,其中D是类类型,可以是   转换为“指向cv B指针”类型的prvalue,其中B是基数   D类(第10条)如果B是无法进入的(第11条)或   模糊(10.2)D的基类,一个需要这个的程序   转换是不正确的。转换的结果是指向   派生类对象的基类子对象。空指针   value将转换为目标类型的空指针值。

但是从

转换的情况下
'Derived **' to 'Base **'

它不是受支持的prvalue转换。

要总结该部分,可以将类型T1的prvalue转换为T2类型的prvalue,iff

  1. T1是一个空指针常量,其值为零或者是std :: nullptr_t类型的prvalue,即将NULL或nullptr赋值给指针类型。
  2. T1的类型是“指向cv T的指针”,其中T是对象类型,T2是“指针”类型 至cv void“ie T *pT = new T(); void *p = pT
  3. T1的类型为“指向cv D的指针”,其中D是类类型,T2的类型是“指针” 至cv B“,其中B是D的基类,即Base* pBase = new Derived()

答案 2 :(得分:0)

你不能这样做,因为它会产生不可检查的限制。当您取消引用myBase时,您将获得Derived**,在语义上不允许您再次为其分配Base。当您使用多重继承时,这会导致实际问题。

如果需要这么多间接,那么您的解决方案就是使用Base**代替。请记住,到达目的地后,您仍可以将“派生”分配给**myBase