C++ Tutorial

C++ Abstract Classes

A pure virtual function makes a class abstract. You cannot construct it; you inherit it.

A function that must be filled in

A virtual function with = 0 is pure virtual. The base class says the name and the signature. It does not say the body. Any class that contains a pure virtual function is abstract: the compiler will not let you make an object of that type.

You inherit the abstract class and write the missing function in each derived class. That is the contract: every concrete shape can answer kind(), but there is no generic shape sitting in memory with a fake answer. Include <string> when the function returns string.

virtual string kind() = 0

Write virtual string kind() = 0; in the base. In each derived class, writestring kind() override and return a label. override asks the compiler to check that you really replaced the base function.

Shape s; does not compile. Circle c; does, because Circle provideskind(). The polymorphism chapter used a base that still had a body. Here the base has none.

Two derived types, one Shape reference

You can still use the abstract type as a reference or a pointer. A function that takesShape& will accept a Circle or a Square. The call tokind() runs the derived version.

Example

#include <iostream>
#include <string>
using namespace std;

class Shape {
public:
  virtual string kind() = 0;
};

class Circle : public Shape {
public:
  string kind() override {
    return "circle";
  }
};

class Square : public Shape {
public:
  string kind() override {
    return "square";
  }
};

void show(Shape& s) {
  cout << s.kind() << endl;
}

int main() {
  Circle c;
  Square q;
  show(c);
  show(q);
  return 0;
}

Output is circle then square. The objects live on the stack.show never names Circle or Square. UncommentingShape s; inside main is a compile error.

Call kind on the objects directly

Direct calls work too. You do not need a helper. The reference version matters when one function must handle every kind of shape without a growing if chain.

Example

#include <iostream>
#include <string>
using namespace std;

class Shape {
public:
  virtual string kind() = 0;
};

class Circle : public Shape {
public:
  string kind() override {
    return "circle";
  }
};

class Square : public Shape {
public:
  string kind() override {
    return "square";
  }
};

int main() {
  Circle c;
  Square q;
  cout << c.kind() << endl;
  cout << q.kind() << endl;
  return 0;
}

A vector of unique_ptr

A vector<Shape> is impossible: the vector would have to construct Shapeobjects. Store owning pointers instead. unique_ptr<Shape> from <memory>holds a derived object and frees it when the pointer dies. Give the base a virtual destructor so that delete through the base pointer runs the right cleanup.

Example

#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;

class Shape {
public:
  virtual string kind() = 0;
  virtual ~Shape() = default;
};

class Circle : public Shape {
public:
  string kind() override {
    return "circle";
  }
};

class Square : public Shape {
public:
  string kind() override {
    return "square";
  }
};

int main() {
  vector<unique_ptr<Shape>> shapes;
  shapes.push_back(make_unique<Circle>());
  shapes.push_back(make_unique<Square>());
  for (const unique_ptr<Shape>& s : shapes) {
    cout << s->kind() << endl;
  }
  return 0;
}

make_unique<Circle>() is C++14 and legal in C++17. s->kind() is a virtual call through the pointer. You do not write delete: unique_ptr does that when the vector is destroyed.

Rules that keep this small

  • Pure virtual: virtual string kind() = 0; in the base.
  • Each concrete class writes kind() with override.
  • Do not construct the abstract type. Construct Circle or Square.
  • Pass Shape& for stack objects. Use unique_ptr<Shape> when you need a list.
  • If you delete through Shape*, the destructor in Shape must be virtual.

When a class should be abstract

Use an abstract base when every derived type must supply a behavior and a default in the base would be a lie. A shape that cannot say what it is should not exist. A file reader that cannot read should not exist. Shared fields and non-virtual helpers can still live in the base; only the required hook is pure.

If the base can provide a reasonable default, a plain virtual function is enough — that was the Animal example in the polymorphism chapter. Pure virtual is the stricter tool.

End of the C++ track

This is the last chapter. Return to /cpp for the full list, or to/cpp/examples for complete programs you can copy. Anything that still feels new compiles at /cpp/try.

Open the unique_ptr listing with Try it in C++. Add a third derived class with its ownkind(), push it into the vector, and run again. The loop does not change.

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.

Physics

An energy you cannot construct

pure virtual value() = 0 makes Energy abstract. You cannot write Energy e;. Kinetic fills in ½ m v². 2 kg at 3 m/s is 9 J. The base is the interface; the derived class is the formula.

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);
  cout << ke.value() << " J" << endl;
  return 0;
}

Maths

A shape that must define area

You cannot construct Shape. Circle must implement area(). Unit circle, r = 1, A = π. The = 0 is the compiler enforcing the exam instruction: state the formula for this shape.

A = π r²

Example

#include <iostream>
using namespace std;

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

class Circle : public Shape {
  double r;
public:
  Circle(double radius) : r(radius) {}
  double area() override { return 3.14159 * r * r; }
};

int main() {
  Circle c(1.0);
  cout << c.area() << endl;
  return 0;
}

FAQ: C++ Abstract Classes

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++ abstract class 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++ abstract class in this C++ C++ lesson (C++ Abstract Classes).

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.