William M. answered 12/15/19
College Professor of C++ with 7+ years of teaching experience
Short version --- a virtual method is a method that can be called using a pointer or reference to a base class, and which will call the correct method in the subclass.
e.g., You have a square class (with a side), that is a subclass of class Shape (that has a center).
You decide all Shapes (Circles, Squares, Rectangles, Triangles) should be able to calculate their area and their perimeter, but they all do this in different ways (pi*r^2 = Acircle, s^2 = Asquare, w*l = Arectangle, ...)
If you have an instance of a Square or a Circle..., and ask for its area() or perimeter() through a pointer or reference to the base class, C++ will still call the correct function in the subclass.
Below is an example of some code to do this. The following four classes/structs are involved: Point(with x_ and y_), Shape(with center_), Circle(with radius_), and Square(with side_).
Questions? Feel free to ask!
#include <iostream> // expand window to see code properly (without wrap around)
#include <cmath> // needed to import M_PI (3.1415...)
// -----------------------------------------------------------
struct Point {
Point() : Point(0.0, 0.0) { }
Point(double x, double y) : x_(x), y_(y) { }
friend std::ostream& operator<<(std::ostream& os,
const Point& pt) {
return os << "(" << pt.x_ << "," << pt.y_ << ")";
}
double x_, y_;
};
// -----------------------------------------------------------
// classes with pure virtual functions cannot be instantiated
//. in Java parlance, they are abstract classes
//. their subclasses MUST instantiate ALL of the pure virtual fns
//. or they also will be abstract classes
// C++ classes with no data and all pure virtual functions
//. would be called interfaces in Java
class Shape {
public:
Shape() : Shape(Point()) { }
Shape(const Point& center) : center_(center) { }
Point center() const { return center_; }
void center(const Point& center) { center_ = center; }
double virtual area() const = 0; // pure virtual aka abstract
double virtual perimeter() const = 0; // pure virtual aka abstract
friend std::ostream& operator<<(std::ostream& os,
const Shape& sh) {
return os << "center=" << sh.center_ << ",area=" << sh.area()
<< ",peri=" << sh.perimeter();
}
private:
Point center_;
};
// -----------------------------------------------------------
class Circle : public Shape {
public:
Circle() : Circle(0.0) { }
Circle(double radius) : Circle(radius, Point()) { }
Circle(double radius, const Point& center)
: Shape(center), radius_(radius) { }
double virtual area() const { return M_PI * radius_ * radius_; }
double virtual perimeter() const { return 2.0 * M_PI * radius_; }
friend std::ostream& operator<<(std::ostream& os, const Circle& c) {
return os << "Circle[radius=" << c.radius_ << ","
<< *dynamic_cast<const Shape*>(&c) << "]";
}
private:
double radius_;
};
// -----------------------------------------------------------
class Square : public Shape {
public:
Square() : Square(0.0) { }
Square(double side) : Square(side, Point()) { }
Square(double side, const Point& center)
: Shape(center), side_(side) { }
double side() const { return side_; }
void side(double side) { side_ = side; }
double virtual area() const { return side_ * side_; }
double virtual perimeter() const { return 4.0 * side_; }
friend std::ostream& operator<<(std::ostream& os,
const Square& sq) {
return os << "Square[side=" << sq.side_ << ","
<< *dynamic_cast<const Shape*>(&sq) << "]";
}
private:
double side_;
};
// -----------------------------------------------------------
int main(int argc, const char* argv[]) {
Circle c1 = Circle(5.0);
Circle c2 = Circle(2.0, Point(3.0, 4.0));
std::cout << "c1 is " << c1 << "\n";
std::cout << "c2 is " << c2 << "\n\n";
Square sq1 = Square(5.0);
Square sq2 = Square(2.0, Point(3.0, 4.0));
std::cout << "sq1 is " << sq1 << "\n";
std::cout << "sq2 is " << sq2 << "\n";
return 0;
}
// ---------------- OUTPUT -----------------------------------
//
//c1 is Circle[radius=5,center=(0,0),area=78.5398,peri=31.4159]
//c2 is Circle[radius=2,center=(3,4),area=12.5664,peri=12.5664]
//
//sq1 is Square[side=5,center=(0,0),area=25,peri=20]
//sq2 is Square[side=2,center=(3,4),area=4,peri=8]
//Program ended with exit code: 0
//
// -----------------------------------------------------------