C ++指针协方差

时间:2016-07-03 00:59:14

标签: c++ pointers covariance

我从来没有想到c ++具有指针协方差,因此可以让你自己在腿上射击:

struct Base
{
    Base() : a(5) {}
    int a;     
};

struct Child1 : public Base
{
    Child1() : b(7) {}
    int b;
    int bar() { return b;}
};

struct Child2 : public Base
{
    Child2(): c(8) {}
    int c;
};

int main()
{
    Child1 children1[2];

    Base * b = children1;

    Child2 child2;

    b[1] = child2; // <------- now the first element of Child1 array was assigned a value of type Child2

    std::cout << children1[0].bar() <<  children1[1].bar(); // prints 57 
}

这是一种未定义的行为吗?有没有办法阻止它或至少有来自编译器的警告?

1 个答案:

答案 0 :(得分:2)

是的,这是未定义的行为。

不,现在,典型的C ++编译器不太可能识别出值得诊断的东西。但是,C ++编译器每年都会变得更聪明。多年后谁知道会是什么样的事情......

然而,一个轻微的狡辩:

b[1] = child2; // <------- now the first element of Child1 array was assigned...

没有。那不是第一个元素。它是第二个元素。 b[0]将是第一个元素。此外,b不是数组,它是指针。它是指向单个元素的指针。它不是指向双元素数组的指针。

这就是未定义行为的来源。

它不是数组的原因是:

Base * b = children1;

children1衰减到Child1 *。如果那个事件结束了,你可以说b将是一个指向双元素数组的指针。

但那并不是事情的结局。衰减的指针被转换为Base *。您可以隐式地将指向子类的指针强制转换为指向超类的指针。但是(现在松散地说)你不能将指向子类数组的指针强制转换为超类数组。因此,b严格地是指向单个元素的指针,b[1]变为未定义的行为。