隐式虚拟传播的原因是什么?
What is the reason of implicit virtual-ness propagation?
我只使用c++ 2~3个月,最近我发现了标识符final,它出现在虚函数之后。直到今天,我还认为省略virtual会阻止虚拟性的传播,但我错了。它隐式传播。
我的问题是这样的。为什么允许隐式传播?为什么存在虚不能使函数虚,而不存在虚不能使函数不虚?在某些情况下是不是更好?还是在虚拟第一次被引入的时候?根据Clifford的回答,甚至有一个编译器会在缺少虚拟时产生警告。
为什么在c
中隐式传播方法的虚拟性我希望上面的链接能回答我的问题,但它没有。
------------新增-------------
有关于询问此功能的有用性的评论。我认为虚函数上的final关键字是使函数去虚拟化的原因。函数不能再被重写,因此派生类必须重新声明函数,无论它是否具有相同的名称。如果final与去虚拟化不同,请帮助我理解。如果final没有区别,那么从引入final这一事实来看,反虚拟化的有用性是不言而喻的。我同意强制显式虚拟会产生bug,但我很好奇是否还有其他原因。
关于为什么存在(或不存在)的答案通常是相当困难的,因为它变成了猜测和意见的问题。然而,最简单的答案可能是最少惊讶原则。要想出一个有意义的、可靠的、可预测的方案是很困难的。
"去虚拟化"一个函数到底是什么意思?如果在运行时调用对象上的"去虚拟化"函数,它会使用指针的静态类型吗?如果静态类型有虚函数,而运行时类型没有,会发生什么?
#include <iostream>
struct A { virtual void f() const { std::cout << "A"; } };
struct B : A { void f() const { std::cout << "B"; } };
struct C : B { virtual void f() const { std::cout << "C"; } };
struct D : C { void f() const { std::cout << "D"; } };
void f(const A& o) { o.f(); }
int main()
{
// "devirtualized" real C++
f(A{}); // "A" "A"
f(B{}); // "A" or "B"? "B"
f(C{}); // "C"? "C"
f(D{}); // oh god "D"
}
还有一个事实是,对于绝大多数设计,虚函数在整个层次结构中必须保持虚。要求它们都使用virtual
将会引入各种难以诊断的bug。c++通常会尽量避免使用那些需要遵守规则才能正确使用的特性。
相关文章:
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 什么是直接 X 虚拟表?
- C++不支持非成员虚拟功能的原因是什么?
- 如果私有虚拟函数被覆盖为派生类中的公共函数,那么问题是什么
- 虚拟析构函数的用途是什么
- 在虚拟继承中构造函数调用的顺序是什么
- shared_ptr控制块内部的虚拟功能是什么?
- 当运算符在方法旁边时,运算符'~'做什么,纯虚拟方法的用途是什么?
- C++11 中默认虚拟析构函数的异常规范是什么?
- 是什么让虚拟功能如此缓慢?C++
- 视觉 C++当我们在基类中使函数成为纯虚拟时,那么在子类中再次使相同的函数虚拟的必要性是什么
- 存储变量的有效方法是什么?(自制虚拟机)
- 在这个"number of elements"宏中进行虚拟添加的目的是什么?
- asm.js规范中提到的c/c++虚拟机是什么
- 传递到虚拟析构函数的这个额外参数是什么?
- 什么是从虚拟基类继承的虚函数的"virtual thunk"?
- 纯虚拟析构函数的目的是什么
- 隐式虚拟传播的原因是什么?
- 编写自定义纯虚拟处理程序:调用堆栈和寄存器时的状态是什么
- 当重写一个方法时,虚拟关键字是什么意思