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

pdr*_*aus 3 c++ casting

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

class Base {};

class Derived : public Base {};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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

void fun( Base*** myBase ) {

    Derived** myDerived = new Derived*();
    *myBase = myDerived;
}
Run Code Online (Sandbox Code Playgroud)

为什么我从C2440: '=' : cannot convert from 'Derived **' to 'Base **'转换Derived*Base*完全没问题?

gha*_*.st 5

答案在于基础指针实际上在C++中的作用.考虑以下简单示例:

struct A { std::uint32_t a; };
struct B { std::uint32_t b; };
struct D : A, B { std::uint32_t d; };
Run Code Online (Sandbox Code Playgroud)

这里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
Run Code Online (Sandbox Code Playgroud)

虽然D期望所有这三个整数,但在考虑这个对象时A,我们只期望第一个,但指针是(数字上)相同的,我们只期望一个更短的对象.但是,当把它想象成一个时B,我们需要指向中间的一个整数.

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

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