C++通过别名指针以静默方式将错误的类型分配给数组元素
C++ silently assigns a wrong type to an array element via an alias pointer
这是有问题的简化代码:
#include <iostream>
using namespace std;
struct A {
virtual void foo() {
cout<<"A::foo()"<<endl;
}
};
struct B : A {
void foo() {
cout<<"B::foo()"<<endl;
}
};
struct C : A {
void foo() {
cout<<"C::foo()"<<endl;
}
};
int main() {
B b[3];
A* a = b;
C c;
a[1] = c; //what's happening here??
a[1].foo(); //prints B::foo() when virtual, and A::foo() when non-virtual
}
我的问题与动态或静态多态性无关,而是与行a[1] = c;
的奇怪分配有关,这似乎完全没有效果。如果a
是数组b
的别名,那么该赋值至少应该给出一个警告,在使用GCC-10编译时不存在警告。 谁能澄清一下编译器在这一行中做了什么?
来自 operator_arithmetic#Additive_operators (强调我的(
- 在任何情况下,如果指向类型与数组元素类型不同,则不考虑 cv 限定条件,则在每个级别上,如果元素本身是指针,则指针算术的行为是未定义的。特别是,指针算术与指向基的指针算术(指向派生对象数组的元素(是未定义的。
所以a[1]
(相当于*(a + 1)
(是未定义的行为。
您可以对b
进行指针算术:
A* b1 = &b[1]; // OK
*b1 = c; // OK, but object slicing
更好的是,引用而不是指针(不检查nullptr,不鼓励使用指针算法(:
A& b1 = b[1]; // OK
b1 = c; // OK, but object slicing
a[1] = c;
此行中有对象切片和未定义的行为。
a[1]
的类型是A
,因此类型的对象C
切片为类型A
的对象。
a[1].foo(); //prints B::foo() when virtual, and A::foo() when non-virtual
B::foo()
打印是因为赋值运算符不会更改对象的类型,因此它不会复制指向vtable
的指针。vptr
将指向B::foo()
。
如果构造C
类型的新对象来代替旧对象,则将更改vptr
和函数C::foo()
将被调用。
只是为了说明,不要在实际代码中这样做:示例
例:
#include <iostream>
using namespace std;
struct A {
virtual void foo() {
cout<<"A::foo()"<<endl;
}
};
struct B : A {
void foo() {
cout<<"B::foo()"<<endl;
}
};
struct C : A {
void foo() {
cout<<"C::foo()"<<endl;
}
};
int main() {
B b[3];
A* a = b;
C c;
// Everything below is undefined behavior and works in this example only because of struct size equality.
a[1] = c; // object slicing and undefined behavior. vptr still points to vtable of B
a[1].foo(); // B::foo()
new(b) C; // creating new object in memory ob b[0] with vptr to vtable of C
a[0].foo(); // C::foo()
}
没有警告,因为对象切片是有效的操作。它可以是有意为之的。
由于"a"是指向基类 A 的指针,因此无法使用索引概念为其赋值。变量"a"只能指向数组的开头,也可以指向单个变量的地址。
在上面的情况下,如果你想分配变量'c',那么你可以通过以下代码分配c的地址,这将打印C::foo((作为输出。
a = &c;
a->foo();
相关文章:
- 我的模板类方法返回错误类型?
- 错误:类型"double()"和"double()"的操作数无效到二进制&quo
- 类型为 "int*" 的参数与 C++ 中错误类型"int**"参数不兼容
- glDrawElements GL 错误类型 = 0x824c,严重性 = 0x9146,消息 = GL_INVALID
- Eclipse/CDT_C++给出"语义错误_"类型XXX无法解决"。项目运行
- turbo 为什么我的C++代码中出现错误类型名称预期"错误?
- "auto"推断出 hashtable_policy.h 中的错误类型
- 设计自己的结果/两者之一:是否应该始终指定成功类型和错误类型
- 如何修复"ctypes"。参数错误:参数 2:<键入"异常.类型错误">:RaspberryPi 中的错误类型"错误
- 在 vscode 上编译错误.类型说明符是 C++11 扩展
- 不允许使用错误类型
- 当读取错误类型时,CIN覆盖我的初始化值
- C++:"错误:类型'const char*'和'const char [28]'的操作数无效到二进制'ope
- 我的代码错误类型警告 1 警告 C4018 和更多错误
- 在shared_from_this()中的错误类型(在继承类中)(是否有dyn.type-ware shared Poi
- 为什么缩小转换范围不能防止错误类型的map.insert()失败
- 程序总是返回二进制'>>':找不到运算符,它采用错误类型的左操作数
- 错误:类型为 '.&' 来自类型的临时 '..*康斯特'
- 涉及将要馈送的向量转换为execvp的错误类型
- C++中是否存在错误类型