具有 C++ 虚函数时的 GDB 不完整类型

Dav*_*vid 3 c++ debugging virtual gdb

我刚刚注意到一些奇怪的事情,当我在类中添加“虚拟关键字”(除构造函数之外的任何函数)时,我无法在 GDB 中显示对象的内容。GDB 说“不完整类型”

这是代码:

////////////////reco.h //////////////

#ifndef RECO_H
#define RECO_H

#include <iostream>
#include <string>

class reco {
    public:
        reco(float weight);
        ~reco(void);

        float getWeight();

    private:
        float weight;
};

#endif
Run Code Online (Sandbox Code Playgroud)

/////////////////reco.cpp //////////////

#include <iostream>
#include <string>

#include "reco.h"

using namespace std;

reco::reco(float weight) {
    weight = weight;
}

reco::~reco(void) {
    cout << "destructor reco" << endl;
}

float reco::getWeight() {
    return weight;
}
Run Code Online (Sandbox Code Playgroud)

////////////// main.cpp //////////////

#include <iostream>
#include <string>

#include "reco.h"

using namespace std;


int main() {
    reco* s = new reco(5.0);
    cout << s->getWeight() << endl;

    delete s;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后使用GDB:

gdb main.exe
breakpoint main.cpp:11 <---- (cout)
run
print *s
$1 = { weight = 5 }
Run Code Online (Sandbox Code Playgroud)

然后,如果我将其中一个函数设置为“虚拟”,然后我重新尝试*s使用 GDB 打印我的指针,它会显示:“不完整类型”

看起来 VTABLE 发生了一些事情,就好像“virtual”关键字隐藏了我的 Reco 类的实现。我知道编译器会进行后期绑定,然后 VTABLE 查找是在运行时完成的,但是当 GDB 调试它时程序已经在运行,对吗?

将“set print vtbl”设置为“on”。

如果我使用ptype s,我会<incomplete type>再次收到该消息。

如果我用 检查地址x/540f80,它会说“无法访问内存”

我不知道为什么仅仅添加这个关键字就会使我的对象的类型不完整?

非常感谢你的帮助 !

我注意到的最后一件事:

虚拟:

 reco.cpp -> g0 and main.cpp -> g = incomplete type
 reco.cpp -> g and main.cpp ->g = ok
Run Code Online (Sandbox Code Playgroud)

没有虚拟

 reco.cpp -> g0 and main.cpp -> g = ok
 reco.cpp -> g and main.cpp ->g = ok
Run Code Online (Sandbox Code Playgroud)

Emp*_*ian 5

reco.cpp -> g and main.cpp ->g = ok

假设-> g您的意思是使用reco.cpp-g标志进行编译,是的,这样,而不是这样做:

g++ -c -g0 reco.cpp
Run Code Online (Sandbox Code Playgroud)

您发现,如果GCC知道您有一个关键方法,它可以优化它必须发出的调试信息量。

如果没有virtual,就没有关键方法,并且 GCC 必须将冗余的调试信息发送到每个编译单元中。这会使您的目标文件更大(它对最终的可执行文件影响很小或没有影响),但即使只有部分目标文件使用调试信息进行编译,您也可以进行调试。