Abstract classes in C++ are very similar, but they are not labelled as abstract. Instead, a C++ class is abstract if any of its methods are abstract. A method is marked as abstract using “=0
” at the end:
class GraphicObject {
int x, y;
⋮
virtual void moveTo(int newX, int newY) {
⋮
}
virtual void draw() = 0;
virtual void resize() = 0;
};
C++ has no direct equivalence to the Java interface
. The closest equivalent would be a purely abstract class:
class OperateCar {
public:
// constant declarations, if any
// method signatures
//
// An enum with values RIGHT, LEFT
virtual
int turn(Direction direction,
double radius,
double startSpeed,
double endSpeed) = 0;
virtual
int changeLanes(Direction direction,
double startSpeed,
double endSpeed) = 0;
virtual
int signalTurn(Direction direction,
bool signalOn) = 0;
virtual
int getRadarFront(double distanceToCar,
double speedOfCar) = 0;
virtual
int getRadarRear(double distanceToCar,
double speedOfCar) = 0;
⋮
// more method signatures
};
in which none of the function members provide actual bodies.
But, as we will see, Java has abstract classes as well. So why does Java need both abstract classes and interfaces? The answer is at the bottom of the tutorial page. C++ permits multiple inheritance. A C++ class can inherit from multiple base classes, thereby picking up the union of all of their members.
But multiple inheritance is complicated and messy (both for programmers and compilers) and the Java designers made an early decision to avoid it. But there are many practical situations where multiple inheritance seems to be the reasonable thing to do.
Java’s interfaces add just enough limitations to the idea of an abstract class that “inheriting” from multiple interfaces does not encounter the same difficulties as inheriting from multiple classes.
A Sample Interface, Relatable
The closest equivalent in C++:
class Relatable {
public:
// this (object calling isLargerThan)
// and other must be instances of
// the same class returns 1, 0, -1
// if this is greater // than, equal
// to, or less than other
virtual int isLargerThan(const Relatable& other) const = 0;
}
Implementing the Relatable Interface
Again, the C++ equivalent:
class RectanglePlus : public Relatable {
public:
int width = 0;
int height = 0;
Point origin;
// four constructors
RectanglePlus() {
origin = new Point(0, 0);
}
RectanglePlus(Point p) {
origin = p;
}
RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
int getArea() const {
return width * height;
}
// a method required to implement
// the Relatable interface
int isLargerThan(const Relatable& other) const {
RectanglePlus& otherRect
= (RectanglePlus&)other;
if (this->getArea() < otherRect.getArea())
return -1;
else if (this->getArea() > otherRect.getArea())
return 1;
else
return 0;
}
};
(Actually, we would probably not keep all the function bodies within the class declaration in C++, as there is no reason to make all of these inline.)
The code on this page is written this way to make a point. In fact, no good Java programmer would declare findLargest and findSmallest this way and then use type casts to Relatable. Instead, they would write:
public Object findLargest(
Relatable obj1,
Relatable obj2) {
if ( (obj1).isLargerThan(obj2) > 0)
return object1;
else
return object2;
}
public Object findSmallest(
Relatable obj1,
Relatable obj2) {
if ( (obj1).isLargerThan(obj2) < 0)
return object1;
else
return object2;
}
because people using these functions should not be expected to read the function bodies in order to find out that they can only be used with parameters that are Relatable
.