First, the function is being declared const, which, as was mentioned above, means that the method promises not to change the underlying object (i.e. the method is constant, the underlying object may or may not be). It has nothing to do with the attributes of the object per se; rather, it has to do with access to the object's attributes via this function.
The virtual keyword is not an issue; it states that derived classes may (or may not; this is not a pure virtual function) override the implementation of IsEmpty(). Nonetheless, the overrides also promise not to change the object.
The statement that"the body of the method is not defined" is wrong, because the function is not declared pure virtual at this level of the class hierarchy. Therefore, there had better be a body for this function, or the compiler will bitch. But lets assume that the function is declared pure virtual, thus:
virtual bool IsEmpty(void) const = 0;
Even then, all you're saying is that you're declaring a function that must be overridden at subsequent levels of the hierarchy, and that everywhere it's overridden, it promises not to change the contents of the object. This, in turn, tells the compiler that it is OK for the compiler to allow invocation of this function on a const object.
Just remember, for functions, const means that the function is not allowed to twiddle the innards of the object.
(And it's not nearly as complex as Todd would have you believe.)