#include <iostream>
using namespace std;
class Z
{
public:
int a;
virtual void x () {}
};
class Y : public Z
{
public:
int a;
};
int main()
{
cout << "\nZ: " << sizeof (Z);
cout << "\nY: " << sizeof (Y);
}
Run Code Online (Sandbox Code Playgroud)
因为Y继承了Z,所以也会有虚表。美好的。但是,它没有任何虚函数,那么 Y 的虚表的内容是什么?
会空吗?
有这个代码:
#include <iostream>
class Base
{
int x;
};
class Derived : virtual public Base
{
int y;
};
int main()
{
std::cout << sizeof(Derived) << std::endl; // prints 12
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我已经读过,当某个类被虚拟继承时,会为类派生创建空虚表,因此内存布局如下:
Derived::ptr to empty vtable
Derived::y
Base::x
Run Code Online (Sandbox Code Playgroud)
它是 12 个字节。问题是 -如果没有任何虚拟方法,这个空的vtable 的目的是什么,它是如何使用的?
在有故障转储的地方调试时,vtable 指针是内存中对象的良好指示器。
我想在 gdb 中做的是能够通过执行类似的操作来查询 vtable
info address 'vtable for Bar'
Run Code Online (Sandbox Code Playgroud)
但是,我找到的唯一方法(不需要对象的有效实例)是对 vtable 使用损坏的名称。
例子:
info address _ZTV3Bar
Run Code Online (Sandbox Code Playgroud)
尝试找出 vtable 损坏的名称并不是世界末日,但它很烦人(即使用 objdump -t myexecutable)。
有没有人知道我可以以一种不那么痛苦的方式找到类型的 vtable 地址的方法(不需要类型的有效实例)?
- 规则:不能要求有问题的对象的有效实例并在对象中找到 vtable 指针。
考虑一个程序,它有一个类,其中包含如下声明的Foo函数:Foo::fn
virtual void fn();
Run Code Online (Sandbox Code Playgroud)
和一个Foo名为 的子类Bar。将Bar::fn这样声明:
virtual void fn() override final;
Run Code Online (Sandbox Code Playgroud)
导致对fninBar或 的子类的调用Bar更加有效,还是只会阻止 的子类Bar被覆盖fn?如果使用 使调用更加高效final,那么最简单、最有效的定义方法是什么,Bar::fn使其功能与 完全相同Foo::fn?
这个问题是关于虚函数调用的(可能的)实现(我相信它被使用gcc)。
考虑以下场景:
f()D 重写B 中声明的虚方法;实例化 F 类型的对象f()D 重写B 中声明的虚方法;实例化 F 类型的对象(这两种场景唯一的区别是B类的继承方式)
在场景 1 中,在对象 B 的 vtable 中,在目标位置处f()现在有一个(非虚拟)thunk 表示:
如果你想调用
f(),首先this用offset
(实际上是D把这个thunk放在那里)
在场景 2 中,在对象 B 的 vtable 中,在指定的位置f()现在有一个(虚拟)thunk 表示:
如果要调用
f(),请首先将this指针更改为存储在的值addr
this(D无法准确告诉B指针需要调整多少,因为它不知道B对象在F对象最终内存布局中的位置)
g++ -fdump-class-hierarchy这些假设是通过结合查看的输出来做出的g++ -S。它们正确吗? …
因此,当在ctor/dtor基类中使用派生类并调用成员函数(包括虚拟)时,无论this是否通过指针,都会调用相关类的函数。
怎么会?vtable在此过程中对象的指针是否以某种方式被更改?因为,据我所知,vtable除非使用多重继承,否则对象中通常只有一个指针。
我有以下代码来举例说明我的意思:
#include <stdio.h>
class B {
public:
B()
{ printf("B constructor!\n"); f(); g(); }
virtual ~B()
{ printf("B destructor!\n"); f(); g(); }
virtual void f()
{ printf("f() in B!\n"); }
void g()
{ printf("g() in B!\n"); }
void h()
{ printf("h() in B!\n"); }
};
class D : public B {
public:
D()
{ printf("D constructor!\n"); f(); g(); }
virtual ~D()
{ printf("D destructor!\n"); f(); g(); }
virtual void f() …Run Code Online (Sandbox Code Playgroud) 如果我创建一个非常简单的类,如下所示:
class A
{
public :
virtual void foo()
{
}
};
Run Code Online (Sandbox Code Playgroud)
(没有虚拟析构函数)是编译器要创建vtable吗?或者现代编译器是否足够聪明以识别这种情况(可能是一个糟糕的复制和粘贴)而不是为这些类添加虚拟表?
所以这是这些编译器错误之一,我无法弄清楚问题的根源.
这是类LocalQualityMeasure,标题
#include <unordered_set>
#include "../clustering/Clustering.h"
#include "../graph/Graph.h"
namespace Project {
/**
* Abstract base class for all local clustering quality measures.
*/
class LocalQualityMeasure {
public:
LocalQualityMeasure();
virtual ~LocalQualityMeasure();
virtual double getQuality(std::unordered_set<node>& C, Graph& G) = 0;
};
} /* namespace Project */
Run Code Online (Sandbox Code Playgroud)
和来源:
#include "LocalQualityMeasure.h"
namespace Project {
LocalQualityMeasure::LocalQualityMeasure() {
}
LocalQualityMeasure::~LocalQualityMeasure() {
// TODO Auto-generated destructor stub
}
} /* namespace Project */
Run Code Online (Sandbox Code Playgroud)
这是一个派生类Conductance,标题
#include <algorithm>
#include "LocalQualityMeasure.h"
namespace Project {
class Conductance: …Run Code Online (Sandbox Code Playgroud) 我知道vtable查找虚函数要比直接函数调用慢很多,因为基类必须搜索vtable来获取派生函数.如果有更多的派生层,如果它会更慢,我就会徘徊.基本上,我的问题如下:
是基础 - > 衍生的(1层继承)虚拟函数调用的速度比 基 - > Derived1 - > Derived2的 - > Derived3 - > DerivedEtc(多层)虚拟函数调用?
class Parent {
public:
virtual void Foo() {}
virtual void FooNotOverridden() {}
};
class Derived : public Parent {
public:
void Foo() override {}
};
int main() {
Parent p1, p2;
Derived d1, d2;
}
Run Code Online (Sandbox Code Playgroud)
(gdb) x/300xb 0x400b30
Run Code Online (Sandbox Code Playgroud)
0x400b30 是d vtable的第一个地址.
0x400b30 <_ZTV7Derived>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x400b38 <_ZTV7Derived+8>: 0x80 0x0b 0x40 0x00 0x00 0x00 0x00 0x00
0x400b40 <_ZTV7Derived+16>: 0x60 0x0a 0x40 0x00 0x00 0x00 0x00 0x00
0x400b48 <_ZTV7Derived+24>: 0x70 0x0a …Run Code Online (Sandbox Code Playgroud)