Linking fails when missing implementation of a not-used pure virtual method
I have a class, which inherits from a class with a pure virtual functions.
Now I need to add another class, which doesn't need some method. I got an idea not to implement this method, instead of always throwing an exception when this method is called, like in the next example :
#include <iostream>
class ibase {
public:
virtual void foo() = 0;
virtual void boo() = 0;
};
class base1 : public ibase {
public:
virtual void foo(){ std::cout<<"base1::foo"<<std::endl; }
virtual void boo(){ std::cout<<"base1::boo"<<std::endl; }
};
class base2 : public ibase {
public:
virtual void foo() { std::cout<<"base2::foo"<<std::endl; }
virtual void boo();
};
int main()
{
ibase *inst1 = new base1;
ibase *inst2 = new base2;
inst1->foo();
inst1->boo();
inst2->foo();
}
But when I tried to compile using next compiler options :
g++ dfg.cpp -ansi -pedantic -Wall
this example produced next output (using g++ 4.3.0) :
/tmp/ccv6VUzm.o: In function `base2::base2()':
dfg.cpp:(.text._ZN5base2C1Ev[base2::base2()]+0x16): undefined reference to `vtable for base2'
collect2: ld returned 1 exit status
Can someone explain why the linking fails? The method boo() is not called.开发者_如何学C
The vtable for base2
is created - you use a base2. The vtable references boo()
- so you need to define it.
10.3/8:
A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).
The One-Definition Rule states that each function that is used
must be defined exactly once. The definition of the term used
includes the following line:
a virtual function is used if it is not pure
That means that all non-pure virtual functions have to be defined even if they aren't called
It fails because the internal vtable needs a place to point to. It doesn't matter if it is called, the vtable is still created.
Create an empty body for the method and you should be good to go.
You have to implement the method in base2
, there is no way around it. Polymorphism is a run time behavior, and there is no way for the linker to know that boo
will never be called. You can simply provide a dummy implementation in the base class instead of making it pure virtual if its not mandatory to implement the method in derived class.
boo may not be invoked in reality but it is used to construct the v-table for base2.
You have to define what behaviour will happen is someone has a base2 and calls boo() on it (via its base class pointer) even if there is no point in the code where this is actually invoked. It is part of the contract of implementing an ibase.
The design is of course flawed, and if you want a class that allows a foo only there should be an interface for that.
If your particular instance is that a call is a no-op then that IS a behaviour for the class.
You just forgot to implement virtual void base2::boo ()
. You have to implement it in order to instantiate base2
class. Otherwise you can leave it pure-virtual by not declaring it in base2
class.
精彩评论