- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
最近遇到了一个 C++ 链接器错误,这对我来说是新的。
libfoo.so: undefined reference to `VTT for Foo'
libfoo.so: undefined reference to `vtable for Foo'
我发现了错误并解决了我的问题,但我仍然有一个烦人的问题:VTT 到底是什么?
旁白: 对于那些感兴趣的人,当您忘记定义在类中声明的第一个虚函数时,就会出现问题。 vtable 进入类的第一个虚函数的编译单元。如果您忘记定义该函数,您会收到一个链接器错误,提示它找不到 vtable,而不是对开发人员更友好的找不到函数。
最佳答案
页面"Notes on Multiple Inheritance in GCC C++ Compiler v4.0.1"现在离线,并且http://web.archive.org没有存档。所以,我在 tinydrblog 找到了文本的拷贝。存档at the web archive .
这里有原始注释的全文,作为“Doctoral Programming Language Seminar: GCC Internals”(2005 年秋季)的一部分,由研究生 Morgan Deters“在圣路易斯华盛顿大学计算机科学系的分布式对象计算实验室”在线发表。
His (archived) homepage :
THIS IS THE TEXT by Morgan Deters and NOT CC-licensed.
摩根威慑网页:
第 1 部分:
The Basics: Single Inheritance
As we discussed in class, single inheritance leads to an object layout with base class data laid out before derived class data. So if classes
A
andB
are defined thusly:class A {
public:
int a;};
class B : public A {
public:
int b;
};then objects of type
B
are laid out like this (where "b" is a pointer to such an object):b --> +-----------+
| a |
+-----------+
| b |
+-----------+If you have virtual methods:
class A {
public:
int a;
virtual void v();
};
class B : public A {
public:
int b;
};then you'll have a vtable pointer as well:
+-----------------------+
| 0 (top_offset) |
+-----------------------+
b --> +----------+ | ptr to typeinfo for B |
| vtable |-------> +-----------------------+
+----------+ | A::v() |
| a | +-----------------------+
+----------+
| b |
+----------+that is,
top_offset
and the typeinfo pointer live above the location to which the vtable pointer points.Simple Multiple Inheritance
Now consider multiple inheritance:
class A {
public:
int a;
virtual void v();
};
class B {
public:
int b;
virtual void w();
};
class C : public A, public B {
public:
int c;
};In this case, objects of type C are laid out like this:
+-----------------------+
| 0 (top_offset) |
+-----------------------+
c --> +----------+ | ptr to typeinfo for C |
| vtable |-------> +-----------------------+
+----------+ | A::v() |
| a | +-----------------------+
+----------+ | -8 (top_offset) |
| vtable |---+ +-----------------------+
+----------+ | | ptr to typeinfo for C |
| b | +---> +-----------------------+
+----------+ | B::w() |
| c | +-----------------------+
+----------+...but why? Why two vtables in one? Well, think about type substitution. If I have a pointer-to-C, I can pass it to a function that expects a pointer-to-A or to a function that expects a pointer-to-B. If a function expects a pointer-to-A and I want to pass it the value of my variable c (of type pointer-to-C), I'm already set. Calls to
A::v()
can be made through the(first) vtable, and the called function can access the member a through the pointer I pass in the same way as it can through any pointer-to-A.However, if I pass the value of my pointer variable
c
to a function that expects a pointer-to-B, we also need a subobject of type B in our C to refer it to. This is why we have the second vtable pointer. We can pass the pointer value(c + 8 bytes) to the function that expects a pointer-to-B, and it's all set: it can make calls toB::w()
through the (second) vtable pointer, and access the member b through the pointer we pass in the same way as it can through any pointer-to-B.Note that this "pointer-correction" needs to occur for called methods too. Class
C
inheritsB::w()
in this case. Whenw()
is called on through a pointer-to-C, the pointer (which becomes the this pointer inside ofw()
needs to be adjusted. This is often called this pointer adjustment.In some cases, the compiler will generate a thunk to fix up the address. Consider the same code as above but this time
C
overridesB
's member functionw()
:class A {
public:
int a;
virtual void v();
};
class B {
public:
int b;
virtual void w();
};
class C : public A, public B {
public:
int c;
void w();
};
C
's object layout and vtable now look like this:+-----------------------+
| 0 (top_offset) |
+-----------------------+
c --> +----------+ | ptr to typeinfo for C |
| vtable |-------> +-----------------------+
+----------+ | A::v() |
| a | +-----------------------+
+----------+ | C::w() |
| vtable |---+ +-----------------------+
+----------+ | | -8 (top_offset) |
| b | | +-----------------------+
+----------+ | | ptr to typeinfo for C |
| c | +---> +-----------------------+
+----------+ | thunk to C::w() |
+-----------------------+Now, when
w()
is called on an instance ofC
through a pointer-to-B, the thunk is called. What does the thunk do? Let's disassemble it (here, withgdb
):0x0804860c <_ZThn8_N1C1wEv+0>: addl $0xfffffff8,0x4(%esp)
0x08048611 <_ZThn8_N1C1wEv+5>: jmp 0x804853c <_ZN1C1wEv>So it merely adjusts the
this
pointer and jumps toC::w()
. All is well.But doesn't the above mean that
B
's vtable always points to thisC::w()
thunk? I mean, if we have a pointer-to-B that is legitimately aB
(not aC
), we don't want to invoke the thunk, right?Right. The above embedded vtable for
B
inC
is special to the B-in-C case. B's regular vtable is normal and points toB::w()
directly.The Diamond: Multiple Copies of Base Classes (non-virtual inheritance)
Okay. Now to tackle the really hard stuff. Recall the usual problem of multiple copies of base classes when forming an inheritance diamond:
class A {
public:
int a;
virtual void v();
};
class B : public A {
public:
int b;
virtual void w();
};
class C : public A {
public:
int c;
virtual void x();
};
class D : public B, public C {
public:
int d;
virtual void y();
};Note that
D
inherits from bothB
andC
, andB
andC
both inherit fromA
. This means thatD
has two copies ofA
in it. The object layout and vtable embedding is what we would expect from the previous sections:+-----------------------+
| 0 (top_offset) |
+-----------------------+
d --> +----------+ | ptr to typeinfo for D |
| vtable |-------> +-----------------------+
+----------+ | A::v() |
| a | +-----------------------+
+----------+ | B::w() |
| b | +-----------------------+
+----------+ | D::y() |
| vtable |---+ +-----------------------+
+----------+ | | -12 (top_offset) |
| a | | +-----------------------+
+----------+ | | ptr to typeinfo for D |
| c | +---> +-----------------------+
+----------+ | A::v() |
| d | +-----------------------+
+----------+ | C::x() |
+-----------------------+Of course, we expect
A
's data (the membera
) to exist twice inD
's object layout (and it is), and we expectA
's virtual member functions to be represented twice in the vtable (andA::v()
is indeed there). Okay, nothing new here.The Diamond: Single Copies of Virtual Bases
But what if we apply virtual inheritance? C++ virtual inheritance allows us to specify a diamond hierarchy but be guaranteed only one copy of virtually inherited bases. So let's write our code this way:
class A {
public:
int a;
virtual void v();
};
class B : public virtual A {
public:
int b;
virtual void w();
};
class C : public virtual A {
public:
int c;
virtual void x();
};
class D : public B, public C {
public:
int d;
virtual void y();
};All of a sudden things get a lot more complicated. If we can only have one copy of
A
in our representation ofD
, then we can no longer get away with our "trick" of embedding aC
in aD
(and embedding a vtable for theC
part ofD
inD
's vtable). But how can we handle the usual type substitution if we can't do this?Let's try to diagram the layout:
+-----------------------+
| 20 (vbase_offset) |
+-----------------------+
| 0 (top_offset) |
+-----------------------+
| ptr to typeinfo for D |
+----------> +-----------------------+
d --> +----------+ | | B::w() |
| vtable |----+ +-----------------------+
+----------+ | D::y() |
| b | +-----------------------+
+----------+ | 12 (vbase_offset) |
| vtable |---------+ +-----------------------+
+----------+ | | -8 (top_offset) |
| c | | +-----------------------+
+----------+ | | ptr to typeinfo for D |
| d | +-----> +-----------------------+
+----------+ | C::x() |
| vtable |----+ +-----------------------+
+----------+ | | 0 (vbase_offset) |
| a | | +-----------------------+
+----------+ | | -20 (top_offset) |
| +-----------------------+
| | ptr to typeinfo for D |
+----------> +-----------------------+
| A::v() |
+-----------------------+Okay. So you see that
A
is now embedded inD
in essentially the same way that other bases are. But it's embedded in D rather than inits directly-derived classes.
关于c++ - 什么是类(class)的 VTT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6258559/
我正在使用视频轨道标签在视频中插入字幕和标题。我有一个 vtt 文件,但我需要在第 1 行和第 2 行之间换行。文本显示在正确的位置,但在一行上。请问如何在演讲者和他的标题之间强制换行? vtt 文件
我有一个简单的 vtt 轨道文件编辑器,其中构建的 vtt 文件内容保存在 var vtt 中. 目前我通过保存vtt的内容来添加轨道。到文件,然后将文件读取为 我想省略保存到文件的步骤,直接将变量
我正在尝试从外部 url 播放电影的字幕,但它不起作用,当我尝试添加本地存储的 vtt 文件时,它就起作用了。下面是代码 上面的代码不起作用。但是当我复制 vtt 的内容时它起作用了。 请
我在从跨域加载 vtt 时遇到问题:“加载 URL 域的不安全尝试...协议(protocol)和端口必须匹配。”我尝试将 crossorigin="true"添加到视频中,它在 chrome 和 f
最近遇到了一个对我来说很陌生的 C++ 链接器错误。 libfoo.so: undefined reference to `VTT for Foo' libfoo.so: undefined refe
我有一个视频标签,我在其中动态传递视频数据,即 src 和 vtt,我只想为当前视频保留 vtt,并删除所有其他 textTracks. 现在切换视频时,与之前播放的视频相关的所有 vtt 开始在视频
我可以使用 ffmpeg v. 3.4.7 从 mp4 文件中提取隐藏式字幕信息: ffmpeg -f lavfi -i movie="sample.mp4[out+subcc]" -map 0:1
我正在尝试让输入文件接受 webvtt 字幕,但是如果我这样做: 它仍然在文件浏览窗口中以 vtt 扩展名显示其他文件。有没有办法对只有 vtt 扩展名的文件进行归档? 最佳答案 我知道回答这个问题
我正在使用 Azure 搜索来搜索存储在 blob 中的文件内容。当我将 Azure 媒体服务 V3 索引器生成的 .vtt 文件包含在我的 Blob 存储中并运行索引器时,它会失败。是因为文件的某些
我想使用 Greasemonkey 为 Openload VTT 字幕添加字幕下载按钮。但是,我不知道如何访问 标签。 以这个 French video clip 为例有英文字幕。当我在 Firefo
最近遇到了一个 C++ 链接器错误,这对我来说是新的。 libfoo.so: undefined reference to `VTT for Foo' libfoo.so: undefined ref
我正在尝试将 VideoJS 用作播放器,并且我喜欢在您使用搜索栏作为视频预览时显示缩略图。我已经完成了生成 vtt 文件和缩略图的工作,因为现在我正在使用 JWPlayer。所以我想使用这个 VTT
如何在 Android 中使用 ExoPlayer2 设置和显示来自 url 的字幕?目前,我用 Kotlin 编写,我使用以下代码设置带字幕的 ExoPlayer: exoPlayer = Simp
有没有什么应用。哪个可以从 .vtt 转换为 .srt 格式?我尝试了不支持 .vtt 的字幕编辑器。如果有人知道任何特定的应用程序。可以用来做同样的事情,请分享。 最佳答案 使用 subconv 你
我正在尝试实现将 MP4 视频上传到 Azure 媒体服务;使其可通过流媒体 URL 进行流媒体播放,以及更重要且具体的问题:上传要在视频中显示的 .VTT 字幕。 我一直致力于将代码集成到此 tut
我有一个 .SRT 文件在 Android 平台上作为子图 block 与视频一起工作。但是该公司有大量视频的 .vtt 文件,而 .srt 文件只有少数。 .vtt 由 iPhone 开发支持。 我
我有几个视频要添加 VTT 隐藏式字幕文件。我在 Blackboard SP11 中通过 JWPlayer 6.8 部署 MP4。我很难准确理解我需要做什么才能让它发挥作用。 MP4 与 VTT 文件
我有一个带有 JW Player 字幕的 VTT 文件,我正在尝试创建交互式文字记录。为此,我需要将 VTT 文件读入数组,然后与数据进行交互。 以下是 VTT 文件的片段: 1 00:00:00 -
我抬头发现了这个 - https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/captioning-conc
我想从 Video.js 对象中加载的章节文件中获取提示。我已经找到了如何获取该轨道,但我需要它的 id 才能访问它。 player.textTracks().getTrackById(); 我找到了
我是一名优秀的程序员,十分优秀!