我确定之前有人问过这个问题,但我根本不知道该搜索什么。所以我很乐意在有人指出我类似的问题后立即删除这个问题。如果有人有更好的建议,我也很乐意重新命名: - )
我想知道以下代码是否按标准定义了行为,或者这可能是编译器/平台依赖的:
struct A
{
virtual void f()
{
std::cout << "A::f()" << std::endl;
}
};
struct B : public A
{
// f() is not implemented here
};
struct C : public B
{
virtual void f() override
{
B::f(); // call f() of direct base class although it is not implemented there
std::cout << "C::f()" << std::endl;
}
};
int main()
{
A* pA = new C();
pA->f();
}
Visual Studio 2017和gcc 5.4.0的输出是:
A::f()
C::f()
编译器是否会在层次结构中向上搜索,直到找到实现?你能链接到C ++标准吗?我通过在纯虚拟中创建f()来测试它,链接器很好地告诉我有一个未解析的符号。我能依靠吗?
据我所知,使用像B :: f()这样的范围运算符总是调用非虚拟版本。所以没有多态现象发生,是吗?
编辑:带有误导性的print语句,将“B :: f()”替换为“C :: f()”。
答案 0 :(得分:3)
指针的动态类型
A* pA = new C();
是C *
。
因此C类中的虚函数被称为
struct C : public B
{
virtual void f() override
{
B::f(); // call f() of direct base class although it is not implemented there
std::cout << "B::f()" << std::endl;
}
};
B类没有重新定义基类A的虚函数。所以在本声明中
B::f(); // call f() of direct base class although it is not implemented there
调用类A中定义的虚函数。这是指向B类虚函数的指针表,其中包含A类中定义的函数的地址。
在此次电话会议中
B::f();
可以访问类B的虚函数表,该表包含类A中函数定义的地址,因为该函数未在B类中被覆盖。
从C ++标准(5.2.2函数调用)
- ...如果所选函数是非虚拟的,或者类成员访问表达式中的id-expression是qualified-id,那么该函数 叫做。否则,它是动态类型的最终覆盖(10.3) 调用对象表达式;这样的呼叫被称为a 虚函数调用。 [
醇>