I'm currently writing a library that has some abstract classes. In addition to checking that the library compiles, I'd like to make sure that all pure virtual methods have been defined in classes that are intended to be concrete. I had hoped that I could get this information from nm
or objdump
, but so far I haven't been able to tell.
Consider the following minimal example:
struct A
{
void f() {}
};
struct B
{
virtual void f() = 0;
};
struct C : public B
{
void f() override {}
};
When I look at the nm
output, I get the following. (I've excluded anything that doesn't relate to one of these classes.)
% nm -C test.so
0000000000001174 W A::f()
000000000000118c W B::B()
000000000000118c W B::B()
0000000000001180 W C::f()
00000000000011aa W C::C()
00000000000011aa W C::C()
0000000000003db0 V typeinfo for B
0000000000003d98 V typeinfo for C
0000000000002003 V typeinfo name for B
0000000000002000 V typeinfo name for C
0000000000003d80 V vtable for B
0000000000003d68 V vtable for C
It's easy to distinguish A
(a class with no virtual methods) from B
and C
. But I want to be able to distinguish the fact that B
is an abstract class whereas C
is concrete.
Obviously, if I have a list of all pure virtual methods, and a map of the class hierarchy, then I could iterate over them and check whether they are defined. (Above, you can see that C::f
is defined, but B::f
is not.) But I was hoping that there would be an automatic way of doing this. (I was hoping that the vtable
or typeinfo
would show up differently above.)
Another way would be to add an extra file where I instantiate one object from every class that I expect to be concrete, and I will get a compiler error if any of them have undefined virtual methods. But this is also annoying.
Clearly, I'm not an expert on ELF or the C object file model in general, so I'd appreciate a useful introduction or reference if the answer turns out to be complicated.
Only you can know which classes these are.
if you have a list of such classes, you can generate a test program along the lines of:
compile and run it. If it doesn't
assert
, you are good.You could in theory also do this at the
test.so
level. You'll need to locate thevtable
for every expected-to-be-concrete classX
, and examine the values in that table. If any value is equal to&__cxa_pure_virtual
, then the class is not concrete.This is complicated by the fact that the
vtable
s are relocated at load time. So you'd have to find thevtable
s, then find relocation records which apply to them, and then search for__cxa_pure_virtual
.Overall, generating a test program is a much easier approach.
Update:
There is no way to do that.
What you could do is find all classes with virtual tables via
nm -D test.so | grep ' _ZTV' | c++filt
. Use that list of all classes to generate the test program, but instead ofassert
ing simply print the class name and the result of the test.Finally filter this list to just the classes where
is_abstract<T>::value
is true. Voilà: you now have the list you were seeking.