我们假设我有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*
?
答案 0 :(得分:5)
答案在于基础指针的强制转换实际上在C ++中的作用。请考虑以下简单示例:
struct A { std::uint32_t a; };
struct B { std::uint32_t b; };
struct D : A, B { std::uint32_t d; };
此处D
有两个基础,A
和B
。但是只有其中一个可以在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
T *pT = new T(); void *p = pT
Base* pBase = new Derived()
答案 2 :(得分:0)
你不能这样做,因为它会产生不可检查的限制。当您取消引用myBase
时,您将获得Derived**
,在语义上不允许您再次为其分配Base
。当您使用多重继承时,这会导致实际问题。
如果需要这么多间接,那么您的解决方案就是使用Base**
代替。请记住,到达目的地后,您仍可以将“派生”分配给**myBase
。