虚函数调用非虚函数,反之亦然
Virtual function calling a non-virtual function and vice versa
我有一个 class A
作为 class B
的基础 class。
我在我的虚拟函数xyz()
中调用了非虚拟函数abc()
, 如下所述。
由于运行时间多态性,B:xyz
被调用——我明白了。
但是,我不明白,为什么后面是B:abc
而不是A:abc
,因为abc
是一个非虚函数。
请注意:我遇到了以下问题:Virtual function calling a non-virtual function。它提到在虚函数中调用 abc()
等同于 this->abc()
,因此输出。但是,我不确定我是否理解这部分。
因为,当我做相反的事情时(即非虚函数调用虚函数),那个时候正确的运行时间多态性就显示出来了。那么 this 指针会发生什么?
//Virtual function calling non-virtual
class A
{
public:
void abc()
{
cout<<"A:abc"<<endl;
}
virtual void xyz()
{
cout<<"A:xyz"<<endl;
abc();
}
};
class B: public A
{
public:
void abc()
{
cout<<"B:abc"<<endl;
}
void xyz()
{
cout<<"B:xyz"<<endl;
abc();
}
};
int main() {
A *obj3 = new B;
obj3->xyz();\
return 0;
}
Output
B:xyz
B:abc
//Non-virtual calling virtual function
#include <iostream>
using namespace std;
class A
{
public:
void abc()
{
cout<<"A:abc"<<endl;
xyz();
}
virtual void xyz()
{
cout<<"A:xyz"<<endl;
}
};
class B: public A
{
public:
void abc()
{
cout<<"B:abc"<<endl;
xyz();
}
void xyz()
{
cout<<"B:xyz"<<endl;
}
};
int main() {
A *obj3 = new B;
obj3->abc();
return 0;
}
Output
A:abc
B:xyz
对 非虚拟 abc
函数的调用在编译时有效地解决:因此,当从 中调用该函数时 class B
的另一个成员函数,该函数的 class B
版本被调用,并传递一个指针 (this
) 指向调用它的对象;类似地,如果从 在 中调用一个 class A
函数,那么将使用 class A
定义。也就是说,对于编译器而言,非虚函数与 class 关联,而不是 class.
的任何特定实例
但是,编译器对您的 virtual xyz
函数的处理方式不同;在这种情况下,函数的引用或指针被添加到 class 定义中(这通常被添加到所谓的 vtable 中,尽管细节是特定于实现的);当创建 class(es) 的任何对象时,它们都会包含该函数指针 and/or vtable 的副本。当编译器看到调用此类虚函数的代码时,它会将其转换为 通过 适当的函数指针的调用;因此,函数 'travels with' actual 对象:该函数是从派生 class 还是从基础 class (在您的代码中)调用是无关紧要的– 调用的函数属于调用它的对象(实例)。
总结:对非虚函数的调用在编译时解析,而对虚函数的调用(概念上)在[=58=时解析] 时间.
要查看此“vtable”的创建,请尝试编译并运行以下代码:
#include <iostream>
class A {
public:
int i;
~A() = default;
void foo() { std::cout << i << std::endl; }
};
class B {
public:
int i;
virtual ~B() = default;
virtual void foo() { std::cout << i << std::endl; }
};
int main()
{
std::cout << sizeof(A) << std::endl;
std::cout << sizeof(B) << std::endl;
return 0;
}
两个 classes 之间的 仅 区别在于一个有虚函数而另一个没有 - 然而这导致了大小的显着差异class 对象:vtable 的大小(可能有一些 'padding' 用于优化数据排列)! (在我的 64 位 Windows 上,使用 MSVC,我得到大小为 4 和 16,但实际值会因编译器和平台而异。)
我有一个 class A
作为 class B
的基础 class。
我在我的虚拟函数xyz()
中调用了非虚拟函数abc()
, 如下所述。
由于运行时间多态性,B:xyz
被调用——我明白了。
但是,我不明白,为什么后面是B:abc
而不是A:abc
,因为abc
是一个非虚函数。
请注意:我遇到了以下问题:Virtual function calling a non-virtual function。它提到在虚函数中调用 abc()
等同于 this->abc()
,因此输出。但是,我不确定我是否理解这部分。
因为,当我做相反的事情时(即非虚函数调用虚函数),那个时候正确的运行时间多态性就显示出来了。那么 this 指针会发生什么?
//Virtual function calling non-virtual
class A
{
public:
void abc()
{
cout<<"A:abc"<<endl;
}
virtual void xyz()
{
cout<<"A:xyz"<<endl;
abc();
}
};
class B: public A
{
public:
void abc()
{
cout<<"B:abc"<<endl;
}
void xyz()
{
cout<<"B:xyz"<<endl;
abc();
}
};
int main() {
A *obj3 = new B;
obj3->xyz();\
return 0;
}
Output
B:xyz
B:abc
//Non-virtual calling virtual function
#include <iostream>
using namespace std;
class A
{
public:
void abc()
{
cout<<"A:abc"<<endl;
xyz();
}
virtual void xyz()
{
cout<<"A:xyz"<<endl;
}
};
class B: public A
{
public:
void abc()
{
cout<<"B:abc"<<endl;
xyz();
}
void xyz()
{
cout<<"B:xyz"<<endl;
}
};
int main() {
A *obj3 = new B;
obj3->abc();
return 0;
}
Output
A:abc
B:xyz
对 非虚拟 abc
函数的调用在编译时有效地解决:因此,当从 中调用该函数时 class B
的另一个成员函数,该函数的 class B
版本被调用,并传递一个指针 (this
) 指向调用它的对象;类似地,如果从 在 中调用一个 class A
函数,那么将使用 class A
定义。也就是说,对于编译器而言,非虚函数与 class 关联,而不是 class.
但是,编译器对您的 virtual xyz
函数的处理方式不同;在这种情况下,函数的引用或指针被添加到 class 定义中(这通常被添加到所谓的 vtable 中,尽管细节是特定于实现的);当创建 class(es) 的任何对象时,它们都会包含该函数指针 and/or vtable 的副本。当编译器看到调用此类虚函数的代码时,它会将其转换为 通过 适当的函数指针的调用;因此,函数 'travels with' actual 对象:该函数是从派生 class 还是从基础 class (在您的代码中)调用是无关紧要的– 调用的函数属于调用它的对象(实例)。
总结:对非虚函数的调用在编译时解析,而对虚函数的调用(概念上)在[=58=时解析] 时间.
要查看此“vtable”的创建,请尝试编译并运行以下代码:
#include <iostream>
class A {
public:
int i;
~A() = default;
void foo() { std::cout << i << std::endl; }
};
class B {
public:
int i;
virtual ~B() = default;
virtual void foo() { std::cout << i << std::endl; }
};
int main()
{
std::cout << sizeof(A) << std::endl;
std::cout << sizeof(B) << std::endl;
return 0;
}
两个 classes 之间的 仅 区别在于一个有虚函数而另一个没有 - 然而这导致了大小的显着差异class 对象:vtable 的大小(可能有一些 'padding' 用于优化数据排列)! (在我的 64 位 Windows 上,使用 MSVC,我得到大小为 4 和 16,但实际值会因编译器和平台而异。)