Skip to main content

Section 19.10 Abstract Classes and Interfaces

Subsection 19.10.1 Abstract Classes

If we try to instantiate the GeometricObject class from the previous section, by doing something like GeometricObject g("black");, we will get an error that says:
error: cannot declare variable ‘g’ to be of abstract type ‘GeometricObject@GeometricObject’
What does it mean to be an “abstract type?” In C++, a class is considered abstract if it has at least one pure virtual function. GeometricObject promises that each GeometricObject should have a getArea() method, but does not actually provide one. Thus there is no way to make a GeometricObject—it is lacking a needed function.
We call classes like this one abstract classes. An abstract class is a class that cannot be instantiated directly because it is missing features. It can only be instantiated through derived classes that provide the missing features. (We might consider making the GeometricObject constructor protected to indicate that it should only be used from subclasses.)

Aside

Although we can not directly make a GeometricObject, it still serves an important role in our design. It can provide concrete code, like GeometricObject does for getColor() and toString(), that subclasses will inherit. It also allows us to write code like checkObject that can work with Rectangles, Circles, and any other GeometricObject subclasses.

Insight 19.10.1.

You need to understand that if a class is abstract, you can not directly make an object of that type. Other than that, there is nothing special you need to do while using them.
In UML, we typically indicate abstract classes in the same way we indicate abstract methods—with italics. We also might annotate it with <<Abstract>>. So GeometricObject should be shown like this in a UML diagram to indicate that it is an abstract class:
GeometricObject is abstract, so we write it in italics and possibly add <<Abstract>>
classDiagram
    class Circle {
    +getArea() double
    }
    class Rectangle {
    +getArea() double

    }
    class `*GeometricObject*` {
    <<Abstract>>
    +getArea()* double
    }
    `*GeometricObject*` <|-- Circle
    `*GeometricObject*` <|-- Rectangle
        
      
Figure 19.10.1. UML for GeometricObjects

Checkpoint 19.10.1.

Which are the true statements about abstract classes?
  • They do not need constructors.
  • Incorrect. They still need constructors for child classes to make use of. (See Listing 19.9.3)
  • They can’t be directly instantiated. (You can’t make an object that is of the abstract type only, you must make objects that are of derived types.)
  • Abstract classes in C++ are those that have one or more abstract methods.
  • Abstract classes can’t have implementation for any methods.
  • Incorrect. Abstract classes can provide implementation for methods. They should do so if there is a logical way to do the job at that level (print in Listing 19.9.3).
  • You can have a reference or pointer to an abstract type (e.g. GeometricObject&).
  • Incorrect. Although you can’t make an instance of an abstract type, you can make a reference to one. It can then be used to refer to any object of a type derived from the abstract one.

Subsection 19.10.2 Interfaces

In programming, the term interface describes a class that is purely abstract—one that provides only abstract functions. An interface declares no member variables and provides no concrete methods (i.e. no function bodies). For example, we might define a Printable interface that declares a pure virtual print function:
class Printable {
public:
    virtual void print() const = 0;
}
Any class that inherits from Printable must provide a definition for the print function. We often call this “implementing an interface”.
An interface provides no code to inherit, but it still allows for code reuse via polymorphism. We can write a function printObject that is able to print any object that has implemented the Printable interface. That object could be a GeometricObject, a Person, or anything else that inherits Printable:
Listing 19.10.2.
class Printable {
public:
    virtual void print() const = 0;
}

class GeometricObject : public Printable {
...other code...
public:
    virtual void print() const {
        cout << "GeometricObject: " << getColor() << endl;
    }
};

class Person : public Printable {
...other code...
public:
    virtual void print() const {
        cout << "Person: " << getName() << endl;
    }
};

void printObject(const Printable& obj) {
    obj.print();
}
Note that the printObject accepts a Printable object. It knows that is-a Printable must have a print function that can be called, so obj.print() is must be allowed. It does not need to know anything else about the specific type of object it is printing.

Insight 19.10.2.

An interface is used to define a contract that implementing classes must follow. In return for agreeing to follow this contract, you enable existing code that understands this contract to interact with your class without any additional modifications.
When diagramming interfaces in UML, we show implementing an interface as a dashed line (instead of the solid line shown for extending a regular or abstract class). We also may want to decorate the class name with <<Interface>>.
Printable is an interface that Geometric Object and Person inherit from.
            classDiagram
                class Circle {
                +getArea() double
                }
                class Rectangle {
                +getArea() double
                }
                class `*GeometricObject*` {
                <<Abstract>>
                +getArea()* double
                +print() void
                }
                class Person {
                +getName() string
                +print() void
                }
                class Student {
                +getMajor() string
                +print() void
                }
                class `*Printable*` {
                <<Interface>>
                +print()* void
                }
                `*GeometricObject*` <|-- Circle
                `*GeometricObject*` <|-- Rectangle
                `*Printable*` <|.. `*GeometricObject*`
                `*Printable*` <|.. Person
                Person <|-- Student
          
        
Figure 19.10.3. UML for the Interface Printable and its implementations

Checkpoint 19.10.2.

What is the difference between an abstract class and an interface?
  • Interfaces are not abstract.
  • Incorrect. Interfaces are a abstract classes. (And ONLY have abstract methods).
  • Interfaces have no member variables or non-abstract methods. Abstract classes can have those.
  • Class declarations do not specify interfaces the class inherits from.
  • Incorrect. Interfaces are listed just like any other base class a class is derived from.
You have attempted of activities on this page.