C++指针协变
C++ pointer 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
}
这是未定义的行为吗?有什么方法可以防止它或至少有来自编译器的警告?
是的,这是未定义的行为。
不,典型的 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]
成为未定义的行为。
我从来没有想到 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
}
这是未定义的行为吗?有什么方法可以防止它或至少有来自编译器的警告?
是的,这是未定义的行为。
不,典型的 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]
成为未定义的行为。