Virtual functions let a base pointer call the derived class implementation.

virtual A `virtual` function can dispatch through a base pointer or reference at runtime.

Virtual Functions

example
virtual_functions.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <string>

class Shape {
public:
    virtual int measure() {
        return 0;
    }

    virtual std::string name() {
        return "shape";
    }
};

class Square : public Shape {
private:
    int side;

public:
    Square(int size) {
        side = size;
    }

    int measure() override {
        return side * side;
    }

    std::string name() override {
        return "square";
    }
};

class Line : public Shape {
private:
    int length;

public:
    Line(int size) {
        length = size;
    }

    int measure() override {
        return length;
    }

    std::string name() override {
        return "line";
    }
};

int main() {
    bool useSquare = true;
    int size = 4;

    Square square(size);
    Line line(size);
    Shape* shape = &line;

    if (useSquare) {
        shape = &square;
    }

    std::cout << "shape=" << shape->name() << std::endl;
    std::cout << "measure=" << shape->measure() << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class Shape {
public:
    virtual int measure() {
        return 0;
    }

    virtual std::string name() {
        return "shape";
    }
};

class Square : public Shape {
private:
    int side;

public:
    Square(int size) {
        side = size;
    }

    int measure() override {
        return side * side;
    }

    std::string name() override {
        return "square";
    }
};

class Line : public Shape {
private:
    int length;

public:
    Line(int size) {
        length = size;
    }

    int measure() override {
        return length;
    }

    std::string name() override {
        return "line";
    }
};

int main() {
    bool useSquare = false;
    int size = 4;

    Square square(size);
    Line line(size);
    Shape* shape = &line;

    if (useSquare) {
        shape = &square;
    }

    std::cout << "shape=" << shape->name() << std::endl;
    std::cout << "measure=" << shape->measure() << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class Shape {
public:
    virtual int measure() {
        return 0;
    }

    virtual std::string name() {
        return "shape";
    }
};

class Square : public Shape {
private:
    int side;

public:
    Square(int size) {
        side = size;
    }

    int measure() override {
        return side * side;
    }

    std::string name() override {
        return "square";
    }
};

class Line : public Shape {
private:
    int length;

public:
    Line(int size) {
        length = size;
    }

    int measure() override {
        return length;
    }

    std::string name() override {
        return "line";
    }
};

int main() {
    bool useSquare = true;
    int size = 2;

    Square square(size);
    Line line(size);
    Shape* shape = &line;

    if (useSquare) {
        shape = &square;
    }

    std::cout << "shape=" << shape->name() << std::endl;
    std::cout << "measure=" << shape->measure() << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class Shape {
public:
    virtual int measure() {
        return 0;
    }

    virtual std::string name() {
        return "shape";
    }
};

class Square : public Shape {
private:
    int side;

public:
    Square(int size) {
        side = size;
    }

    int measure() override {
        return side * side;
    }

    std::string name() override {
        return "square";
    }
};

class Line : public Shape {
private:
    int length;

public:
    Line(int size) {
        length = size;
    }

    int measure() override {
        return length;
    }

    std::string name() override {
        return "line";
    }
};

int main() {
    bool useSquare = true;
    int size = 6;

    Square square(size);
    Line line(size);
    Shape* shape = &line;

    if (useSquare) {
        shape = &square;
    }

    std::cout << "shape=" << shape->name() << std::endl;
    std::cout << "measure=" << shape->measure() << std::endl;
    return 0;
}
  1. useSquare ← 1, size ← 4

    51int main() {52    bool useSquare→ 1 = true; //@useSquare=false53    int size→ 4 = 4; //@size=2, 65455    Square square(size4);56    Line line(size);
  2. side ← 4

    19public:20    Square(int size4) {21        side→ 4 = size4;22    }
  3. square ← (empty)

    55Square square→ (empty)(size4);56Line line(size4);57Shape* shape = &line;
  4. length ← 4

    37public:38    Line(int size4) {39        length→ 4 = size4;40    }
  5. line ← (empty), shape ← ⟨addr A⟩

    55Square square(size);56Line line→ (empty)(size4);57Shape* shape→ ⟨addr A⟩ = &line(empty);
  6. shape ← ⟨addr B⟩

    59if (useSquare1) {60    shape→ ⟨addr B⟩ = &square(empty);61}
  7. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape->measure() << std::endl;
  8. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65return 0;
    outputshape=square
  9. int measure() override

    24int measure() override {25    return side4 * side;26}
  10. std::cout << "measure=" << shape->measure() << std::endl;

    63    std::cout << "shape=" << shape->name() << std::endl;64    std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65    return 0;66}
    outputmeasure=16
  1. useSquare ← 0, size ← 4

    51int main() {52    bool useSquare→ 0 = false;53    int size→ 4 = 4;5455    Square square(size4);56    Line line(size);
  2. side ← 4

    19public:20    Square(int size4) {21        side→ 4 = size4;22    }
  3. square ← (empty)

    55Square square→ (empty)(size4);56Line line(size4);57Shape* shape = &line;
  4. length ← 4

    37public:38    Line(int size4) {39        length→ 4 = size4;40    }
  5. line ← (empty), shape ← ⟨addr A⟩

    55Square square(size);56Line line→ (empty)(size4);57Shape* shape→ ⟨addr A⟩ = &line(empty);5859if (useSquare) {60    shape = &square;61}6263std::cout << "shape=" << shape⟨addr A⟩->name() << std::endl;64std::cout << "measure=" << shape->measure() << std::endl;
  6. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr A⟩->name() << std::endl;64std::cout << "measure=" << shape⟨addr A⟩->measure() << std::endl;65return 0;
    outputshape=line
  7. int measure() override

    42int measure() override {43    return length4;44}
  8. std::cout << "measure=" << shape->measure() << std::endl;

    63    std::cout << "shape=" << shape->name() << std::endl;64    std::cout << "measure=" << shape⟨addr A⟩->measure() << std::endl;65    return 0;66}
    outputmeasure=4
  1. useSquare ← 1, size ← 2

    51int main() {52    bool useSquare→ 1 = true;53    int size→ 2 = 2;5455    Square square(size2);56    Line line(size);
  2. side ← 2

    19public:20    Square(int size2) {21        side→ 2 = size2;22    }
  3. square ← (empty)

    55Square square→ (empty)(size2);56Line line(size2);57Shape* shape = &line;
  4. length ← 2

    37public:38    Line(int size2) {39        length→ 2 = size2;40    }
  5. line ← (empty), shape ← ⟨addr A⟩

    55Square square(size);56Line line→ (empty)(size2);57Shape* shape→ ⟨addr A⟩ = &line(empty);
  6. shape ← ⟨addr B⟩

    59if (useSquare1) {60    shape→ ⟨addr B⟩ = &square(empty);61}
  7. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape->measure() << std::endl;
  8. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65return 0;
    outputshape=square
  9. int measure() override

    24int measure() override {25    return side2 * side;26}
  10. std::cout << "measure=" << shape->measure() << std::endl;

    63    std::cout << "shape=" << shape->name() << std::endl;64    std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65    return 0;66}
    outputmeasure=4
  1. useSquare ← 1, size ← 6

    51int main() {52    bool useSquare→ 1 = true;53    int size→ 6 = 6;5455    Square square(size6);56    Line line(size);
  2. side ← 6

    19public:20    Square(int size6) {21        side→ 6 = size6;22    }
  3. square ← (empty)

    55Square square→ (empty)(size6);56Line line(size6);57Shape* shape = &line;
  4. length ← 6

    37public:38    Line(int size6) {39        length→ 6 = size6;40    }
  5. line ← (empty), shape ← ⟨addr A⟩

    55Square square(size);56Line line→ (empty)(size6);57Shape* shape→ ⟨addr A⟩ = &line(empty);
  6. shape ← ⟨addr B⟩

    59if (useSquare1) {60    shape→ ⟨addr B⟩ = &square(empty);61}
  7. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape->measure() << std::endl;
  8. std::cout << "shape=" << shape->name() << std::endl;

    63std::cout << "shape=" << shape⟨addr B⟩->name() << std::endl;64std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65return 0;
    outputshape=square
  9. int measure() override

    24int measure() override {25    return side6 * side;26}
  10. std::cout << "measure=" << shape->measure() << std::endl;

    63    std::cout << "shape=" << shape->name() << std::endl;64    std::cout << "measure=" << shape⟨addr B⟩->measure() << std::endl;65    return 0;66}
    outputmeasure=36