An abstract class is basically an incomplete definition of a class, and it contains at least one pure virtual member method. It is a binding agreement between the class that derives from the abstract class and the class that calls the methods of that derived class.
In every other way, an abstract class is the same as a normal class. It can have variables, methods, properties, constructors, and destructors. The only thing it can't do is instantiate an object from itself. Thus, it can't be used as a parameter or return type. However, pointers and references to abstract classes can be used as a parameter or return type.
You might be wondering why you would need a constructor if you can't create an abstract class. The constructor of an abstract class serves the same purpose it does in a normal class: to initialize the member variables. There's one catch, though. The only place you can put an abstract class constructor is in the derived class's initializer list. Because the constructor only needs to be accessed by the deriving class, it's safest to declare the constructor as protected.
Any class that derives from an abstract class must implement the pure virtual function or it will become an abstract class itself.
Any class that has pure virtual methods is abstract. In fact, even though Managed C++ has added the keyword __abstract to declare a class as abstract, the keyword is optional and not really needed. What it does is simply make the class notation explicit. It also makes your code more readable, as now you can see that a class is abstract from its initial declaration and you do not have to search the class for pure virtual methods.
Because an abstract class has to be inherited, obviously a __sealed class is not allowed, but it is legal to __seal a virtual method, if the abstract class implements it.
To show abstract classes in action, Listing 3-15 shows an abstract class defined with a constructor and two methods, one of which is a pure virtual method. Another class inherits this class and seals Method1, but because it does not implement Method2, it too is abstract. Finally, this second abstract class is called by a third class, which implements the pure virtual function. Because the class now has all classes implemented, it can be instantiated. The example also shows how to pass an abstract class pointer as a parameter.
Listing 3-15: Abstract Classes in Action
#using <mscorlib.dll> using namespace System; __abstract __gc class AbstractExClass { protected: Int32 AbstractVar; AbstractExClass(Int32 val): AbstractVar(val) {} public: virtual void Method1() = 0; // unimplemented method virtual void Method2() = 0; // unimplemented method void Method3() { Console::WriteLine(AbstractVar.ToString()); } }; __abstract __gc class MidAbstractExClass : public AbstractExClass { public: __sealed void Method1() { Console::WriteLine((AbstractVar * 3).ToString()); } protected: MidAbstractExClass(Int32 val) : AbstractExClass(val) {} }; __gc class DerivedExClass : public MidAbstractExClass { public: DerivedExClass(Int32 val) : MidAbstractExClass(val) {} void Method2() { Console::WriteLine((AbstractVar * 2).ToString()); } }; void testMethod(AbstractExClass &aec) { aec.Method1(); aec.Method2(); aec.Method3(); } Int32 main(void) { AbstractExClass &Ab1 = *new DerivedExClass(5); Ab1.Method1(); Ab1.Method2(); Ab1.Method3(); AbstractExClass &Ab2 = *new DerivedExClass(6); testMethod(Ab2); DerivedExClass *dc = new DerivedExClass(7); testMethod(*dc); return 0; }
Figure 3-15 shows the results of this little program.
Figure 3-15: Results of AbstractEx.exe