If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class?
No.
Do I have to have "virtual void
f() = 0;" instead?
If you want the class to be abstract. Doing so has other
repercusions, however.
In practice, "abstract" represents a restriction on what can be
done with the class. It's never something you absolutely need
from a programming point of view; the fact that a class is
abstract is rather a consequence of the fact that you need pure
virtual functions.
I think declaring a function as "=0" is the same
as not giving its definition, is this right?
Not at all. The rules are far more subtle. Declaring a
function pure virtual (i.e. appending "= 0" to its declaration)
has several effects:
1. it makes the class abstract,
2. it means that anytime dynamic lookup of the function
resolves to the function in this class, you have undefined
behavior, and
3. it means that you are not required to provide a definition
of the function unless it is explicitly called.
Concerning these points;
1. You cannot create an instance of an abstract class.
Attention, however. This does not mean that there are never
objects which have the dynamic type of the class. During
construction and destruction, the dynamic type evolves to
alway be that of the constructor or destructor. So if you
call a pure virtual function (directly or indirectly) while
executing the constructor or the destructor, the dynamic
resolution will result in the pure virtual function. Which
leads to point 2:
2. It's undefined behavior. From a quality of implementation
point of view, I would expect the program to abort, with an
error message, and this is, in fact, what most compilers do.
But it's not guaranteed, and you cannot count on it.
Literally anything can happen, and you must absolutely avoid
the case.
3. Normally, if a function is virtual, it is considered to be
used, regardless of whether you ever actually call it or
not. And if a function is used, it must defined, somewhere.
If a function is pure virtual, however, it is not
automatically considered used, and so a definition is only
required if you actually do use it; since it cannot be found
by dynamic lookup (point 2), the only way to use it is to
call it explicitly, i.e. Base::f(). Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator. The constructors
are irrelevant here, since you cannot have a pure virtual
constructor, but if you have a pure virtual destructor, you
will have to provide a definition, and if you have a pure
virtual assignment operator (which I definitly don't
recommend), you will have to provide a definition if any of
the derived classes wants to use the default assignment
operator.
In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it?
Because the compiler will generate a call to it in the
destructor of derived class, see point 3 above.
class B{
virtual ~B();
virtual void f() = 0;
};
Then my compiler still asks me to define ~B(). However, I
will never create an object of type B!
No, but the compiler generates calls to the destructor in the
destructors of the derived classes. If you never derive from B,
you don't have to provide a definition of ~B(), but if you can't
instantiate the class, and you can't derive from it, what can
you do with it.
Additionally, I don't think I can declare virtual constructor,
but it seems I can't make a pure constructor like
class C{
C() = 0;
virtual void f()=0;
};
You can only make a virtual function pure. Since constructors
can't be virtual, they can't be pure.
Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?
Because constructors aren't virtual.
Moreover, is there any function or operator that can't be virtual,
just like constructors?
Static functions, including member operator new() and member
operator delete().
The above is rather abstract. Perhaps a quick explination of
the motivation behind it, or rather, how a compiler typically
implements it, would help:
The usual implementation of virtual functions (forgetting
multiple inheritance, etc., for the moment) is to define a table
of "function addresses" (in quotes, because we're at the
assembler level here, and this has nothing to do with any C++
type) for each class with at least one virtual function, and to
add a hidden pointer to this table in each class. (The table is
traditionally refered to as a vtbl, and the pointer as vptr,
from their names in the CFront generated C code.) A virtual
function is always considered "used" because the compiler must
take its address (which requires a definition) in order to
generate the vtbl. The point of declaring a function pure
virtual is to tell the compiler that it will not be called for
an object of this type, so the compiler does not need to take
its address and put it in the vtbl. (One early compiler I used
put a null pointer in its place, so the program silently died.
Most modern compilers put the address of a special function,
which outputs an error message and aborts, so you know why the
program died. And optimization may cause other effects.)
Because the compiler doesn't need the address for the vtbl, you
don't have to provide a definition.
From the compiler point of view, there would be no problem
allowing the instantiation of a class with a pure virtual
function. But a virtual function which you cannot call
virtually is almost certainly an error, so the language declares
the class abstract, and forbids its instantiation.