我了解虚函数和vTable,因此请问这是一个琐碎的问题。...
基于人们所解释的vTable和vPtr的概念,我理解并期望下面的程序可以工作,但会出错。
问题陈述: 在下面的示例中,按照理解,类B应该有一个包含函数f2()和f3()的“ vTable”。是不是 (因为f2()从A类继承但被覆盖,并且f3在B类本身中是虚拟的)
但是当进行函数调用“ obj-> f3(); ”时,出现如下所示的错误,我仍然想知道为什么会这样吗?
错误: 在函数'int main()'中: 31:10:错误:“类A”没有名为“ f3”的成员
// Example program
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
void f1() {cout<<"A::f1"<<endl;}
virtual void f2() {cout<<"A::f2"<<endl;}
};
class B: public A
{
public:
void f1() {cout<<"B::f1"<<endl;}
void f2() {cout<<"B::f2"<<endl;}
virtual void f3() {cout<<"B::f3"<<endl;}
};
int main()
{
A* obj = new B();
obj->f1(); // Early Binding (EB)
obj->f2(); // Late Binding (LB)
obj->f3(); // Error (though was expecting LB since f3 is virtual)
}
错误: 在函数'int main()'中:31:10:错误:'class A'没有名为'f3'的成员
答案 0 :(得分:3)
实现细节(vtable与否)无关紧要。在标准(以及因此是编译器)的眼中,您的代码无效,因为A
没有方法f3()
并且obj
的类型为A*
,仅此而已
答案 1 :(得分:0)
在尝试描述任何C ++指令的语义之前,您需要返回C ++的最基本概念(它们是C基本概念的复杂变体): C ++是具有静态特性的编译语言。 。
类似于C中的C ++,在编译时会查找并绑定名称:使用的任何名称都必须引用可见的声明。编译器只能找到由表达式指定的类中的名称。 (表达式是语法构造,它们存在于编译时。)
在静态类型语言中,表达式类型是静态的,并根据声明在每个函数内部进行计算。
C ++还通过虚函数支持动态多态。不会使语言动态输入;基本原理没有改变:每个表达式的类型都是通过根据其语法和可见声明(对象,函数等的可见名称)应用规则来确定的。使用动态多态性多态对象的类型(对象在运行时存在),即构造的类型(构造函数类的名称) (用于构造对象的操作)。确定虚拟调用将调用哪个函数体。有时称为后期绑定。
在您的格式错误的代码中,后期绑定不是问题,它甚至不会编译,无法运行,并且在运行时不会在任何多态对象上调用任何函数:
obj->f3(); // Error (though was expecting LB since f3 is virtual)
当obj
的指针类型为obj->something
时与(*obj).something
相同;并且obj
是定义为
A* obj = (...something not relevant for the argument...);
因此obj
的类型为A*
,而*obj
的类型为A
,其类型定义为:
class A
{
public:
void f1() {cout<<"A::f1"<<endl;}
virtual void f2() {cout<<"A::f2"<<endl;}
};
在由表达式f3
指定的类中没有可见的任何成员*obj
的声明。 因此调用的格式不正确。在编译时无效,编译器拒绝了。
这是该不良表格的所有相关分析的全部。其余的与静态类型的语言无关。没有在 relevant 代码中命名的派生类(这只是obj
的声明类型,以及确定在哪里进行名称查找的表达式*obj
)无关紧要。这是静态类型的 essence 。
此外,使代码的有效性取决于未直接命名的其他类(这些类可能是某些表达式引用的运行时构造的对象的类型),即使在编译时也无法检测到简单的错字时间。