C++ Tutorial

C++ Polymorphism

virtual functions let a base pointer call the derived version. One interface, many types.

One call, the right version

You have an Animal and two kinds of animal. You want speak() to mean bark for a dog and meow for a cat, even when the code that calls speak only knows it has an Animal.

That is polymorphism: the same name, different behavior chosen from the real type of the object. In C++ you mark the base function virtual and the derived function override.

Without virtual, the base wins

If speak is not virtual, a call through an Animal* always runs Animal::speak, even when the pointer points at a Dog. The compiler binds the call to the type of the pointer, not the object.

You will see this the first time you store mixed types behind a base pointer and every one of them prints the base message. The fix is one keyword on the base function.

virtual speak() and override

Write virtual on the function in the base class. In the derived class, write the same signature and add override. override asks the compiler to check that you really replaced a virtual function. A typo in the name then fails at compile time instead of silently doing nothing.

Example

#include <iostream>
using namespace std;

class Animal {
public:
  virtual void speak() {
    cout << "..." << endl;
  }
};

class Dog : public Animal {
public:
  void speak() override {
    cout << "woof" << endl;
  }
};

class Cat : public Animal {
public:
  void speak() override {
    cout << "meow" << endl;
  }
};

int main() {
  Dog d;
  Cat c;
  d.speak();
  c.speak();
  return 0;
}

Direct calls on d and c already pick the derived version. Virtual matters most when the static type is the base.

A base pointer calls the derived function

Take the address of a Dog and store it in an Animal*. Call speak through that pointer. Because speak is virtual, the program runs Dog::speak.

Example

#include <iostream>
using namespace std;

class Animal {
public:
  virtual void speak() {
    cout << "..." << endl;
  }
};

class Dog : public Animal {
public:
  void speak() override {
    cout << "woof" << endl;
  }
};

int main() {
  Dog d;
  Animal* p = &d;
  p->speak();
  return 0;
}

p is typed as Animal*. The object is still a Dog. The arrow-> calls a method through a pointer. You do not need new for this: the dog lives on the stack, and p only holds its address.

A base reference works the same way: Animal& r = d; r.speak();. Use a pointer when you might reseat it, a reference when it always names the same object.

Several types, one loop

Put pointers to different animals in a small list. The loop only knows Animal*. Each object still speaks as itself.

Example

#include <iostream>
using namespace std;

class Animal {
public:
  virtual void speak() {
    cout << "..." << endl;
  }
};

class Dog : public Animal {
public:
  void speak() override {
    cout << "woof" << endl;
  }
};

class Cat : public Animal {
public:
  void speak() override {
    cout << "meow" << endl;
  }
};

int main() {
  Dog d;
  Cat c;
  Animal* zoo[2] = {&d, &c};
  for (int i = 0; i < 2; i++) {
    zoo[i]->speak();
  }
  return 0;
}

That is the payoff. Drawing code, UI widgets, and game entities all use this pattern: store base pointers, call one virtual method, get the derived work.

Rules that keep this small

  • Mark the function virtual in the base. Once is enough; derived classes inherit that.
  • Write override on the replacement. C++11 and later, including C++17 on StudyGrid.
  • The signatures must match: return type, name, and parameters.
  • Do not delete through a base pointer until you have a virtual destructor. This chapter does not allocate.

Compile these at /cpp/try. Next: reading and writing files with fstream.

Worked examples

The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.

Open them in the C++ editor at /cpp/try. Change one measurement and check whether the result still has the right unit.

Maths

Area through a base pointer

virtual area() lets a Shape* call the Circle version. One interface, many types. The square of side 3 has area 9. The pointer type is Shape; the object type is Square.

A = s²

Example

#include <iostream>
using namespace std;

class Shape {
public:
  virtual double area() = 0;
  virtual ~Shape() {}
};

class Square : public Shape {
  double s;
public:
  Square(double side) : s(side) {}
  double area() override { return s * s; }
};

int main() {
  Square sq(3.0);
  Shape *p = &sq;
  cout << p->area() << endl;
  return 0;
}

Physics

KE or PE through one pointer

Both are energies in joules. A base Energy with virtual value() lets you store different formulas behind one pointer. 2 kg at 3 m/s is 9 J of KE.

KE = ½ m v²

Example

#include <iostream>
using namespace std;

class Energy {
public:
  virtual double value() = 0;
  virtual ~Energy() {}
};

class Kinetic : public Energy {
  double m, v;
public:
  Kinetic(double mass, double speed) : m(mass), v(speed) {}
  double value() override { return 0.5 * m * v * v; }
};

int main() {
  Kinetic ke(2.0, 3.0);
  Energy *e = &ke;
  cout << e->value() << " J" << endl;
  return 0;
}

FAQ: C++ Polymorphism

Common questions about this page.

What is the StudyGrid C++ tutorial?

The StudyGrid C++ tutorial is a full beginner-to-advanced track: syntax, types, input, loops, functions, classes, the STL, templates, maps, and lambdas. Each chapter has copy-and-run examples.

Should I run c++ polymorphism examples locally for better learning?

Yes. Use the browser editor on StudyGrid for a quick check, then Download the example and run it on your computer. Local runs show real errors and the real toolchain, which is one of the fastest ways to learn c++ polymorphism in this C++ C++ lesson (C++ Polymorphism).

Is the C++ editor the same as Try Python or Try HTML?

No. Try C++ compiles with g++ at /cpp/try and shows stdout plus compiler messages. Try Python stays at /try. Try HTML stays at /html/try. C++ lessons never open those editors.

Do I need to install a compiler to learn C++?

No. Open a chapter, click Try it in C++, and compile in the browser. You can also download a .cpp file and compile locally with g++.

Where should I start the C++ tutorial?

Start at C++ Intro, then Get Started and Syntax. After the first program, continue to output, variables, and if-else. After classes, open C++ Examples, then templates, map, and lambdas. Use Next at the bottom of each chapter.

Is the C++ tutorial free?

Yes. The C++ workshop on StudyGrid (studygrid.in) is free: dashboard, chapters, and the compile-and-run editor.