【发布时间】:2016-03-18 19:51:54
【问题描述】:
在内置 MySQL 存储引擎的实现中,存在具有以下结构的类:
// omitting lots of code across several files
class handler {
protected:
virtual void notify_table_changed();
};
void handler::notify_table_changed() {
// implementation
}
class ha_innopart : public handler {
void notify_table_changed();
};
// NB: no implementation for ha_innopart!
据我了解,这应该会给出一个链接错误,因为ha_innopart 将缺少notify_table_changed() 的 vtable 条目。这是supported by the gcc FAQ。
相关 MySQL 类的链接:
-
handler.h: https://github.com/mysql/mysql-server/blob/67d52e7c7a1a23424e39273cbb6f5f9d56fda8d1/sql/handler.h#L3518-L3523 -
handler.cc: https://github.com/mysql/mysql-server/blob/67d52e7c7a1a23424e39273cbb6f5f9d56fda8d1/sql/handler.cc#L4736-L4744 -
ha_innopart.h: https://github.com/mysql/mysql-server/blob/67d52e7c7a1a23424e39273cbb6f5f9d56fda8d1/storage/innobase/handler/ha_innopart.h#L306-L307
以下代码重现了我所看到的问题:
#include <stdio.h>
class A {
public:
virtual int foo();
};
class B : public A {
public:
int foo(); // Will work by commenting out this line...
};
int A::foo() { return 42; }
// int B::foo() { return 24; } // ...or uncommenting this line.
int main(int argc, char **argv) {
B b;
::printf("%d\n", b.foo());
}
编译得到:
$ g++ test.cc -o test && ./test
/tmp/ccAiCHry.o: In function `main':
test.cc:(.text+0x32): undefined reference to `B::foo()'
/tmp/ccAiCHry.o: In function `B::B()':
test.cc:(.text._ZN1BC2Ev[_ZN1BC5Ev]+0x1f): undefined reference to `vtable for B'
collect2: ld returned 1 exit status
如上述 cmets 所述,可以通过注释掉 B 的 foo() 声明或为 B 提供 foo() 的实现来解决此问题。这些案例的输出分别是:
$ !!
g++ test.cc -o test && ./test
42
$ !!
g++ test.cc -o test && ./test
24
那么,MySQL没有实现ha_innopart::notify_table_changed(),怎么还能编译链接不出错呢?
【问题讨论】:
-
它要么未使用,要么在库中。拿一个使用它的程序,查看链接它的库,然后遍历库中的符号,直到找到它。像“nm”这样的东西会帮助你sourceware.org/binutils/docs/binutils/nm.html