英文:
Exception pointer call
问题
B类对象的成员函数为什么可以使用指向A类对象的指针调用,而不会引发异常?
英文:
struct A {
bool testA(int) {
std::cout << "A" << std::endl;
return true;
};
};
struct B {
void testB() {
std::cout << "B" << std::endl;
};
};
int main() {
A a;
((B*)(&a))->testB();
return 0;
}
Why can a member function of a B-class object be called with a pointer to an A-class object without throwing an exception?
答案1
得分: 1
C++核心语言不使用异常来表示程序员编写的代码违反语言规则,除非在非常特殊的情况下,违规是可以在不增加运行时开销的情况下检测到的,比如std::bad_new_array_length
。
相反,通常的做法是"未定义行为"。通常情况下,不能期望实现会检查你是否遵守规则,因为这样做会使代码变慢。例如,在成员函数调用的情况下,捕捉像OP所示的错误的一种策略是为每个对象分配一个vptr和RTTI信息,而不仅仅是多态类型的对象。然后,每个成员函数调用在运行时都可以查找类型信息并将其与静态所需类型(在本例中为B
)进行比较。请注意,这种实现策略会增加每个对象的大小,增加每个可执行映像的大小(因为生成RTTI信息),并增加每个成员函数调用的时间。换句话说,即使程序是正确的,它也会显著降低程序的性能。因此,C++标准不强制执行这种性能下降,而是让实现在假设对象表达式确实表示适当类型的对象的情况下编译成员函数调用。如果违反了这一规则,你将得到相应的结果。
(一些实现使用这种自由来执行激进的"时间旅行"优化,但我不会在这里详细介绍。)
英文:
The C++ core language does not use exceptions to signal that the programmer has written code that breaks a language rule, except in very specific cases where the violation is detectable without run-time overhead, such as std::bad_new_array_length
.
Instead, the usual approach is "undefined behaviour". The implementation usually cannot be expected to check whether you are following the rules, because doing so would make the code slower. For example, in the case of a member function call, one strategy to catch bugs like what is shown by the OP would be to allocate a vptr and RTTI information for every object, not only objects with polymorphic types. Then, every member function call, at runtime, could look up the type info and compare it with the statically required type (in this case, B
). Notice that this implementation strategy would increase the size of every object, increase the size of every executable image (due to the generation of RTTI information), and increase the amount of time taken for each member function call. In other words, it would significantly worsen the performance of the program even if the program is correct. So, instead of mandating this kind of pessimization, the C++ standard just lets implementations compile member function calls under the assumption that the object expression really denotes an object of appropriate type. If you violate this rule, you get what you get.
(Some implementations use this freedom to perform aggressive "time travel" optimizations, but I won't get into that here.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论