Refactoring C++ Classes

See how we can use refactoring to keep our code clean, simple and easy to update
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

3D art showing a maid cleaning
Ryan McCombe
Ryan McCombe
Posted

When we write code, experiment and try different things to get our functionality to work, the solution we're left with isn't always optimal. It can be unneccessarily complex, or difficult to expand on in the future.

Refactoring is the process of taking code that already works, and improving it to make things simpler or more understandable.

Without constantly reviewing and refactoring our code to manage its complexity, the software we create quickly becomes limited.

If our functions and classes get too complex, it becomes increasingly difficult to add new features or fix bugs.

This can grind our project to a halt. To build more complex projects, we need to be able to manage that complexity. Good design, and proactive refactoring are how we do that.

Test your Knowledge

Which of the following are examples of refactoring?

When to Refactor

It is a lot easier to refactor code immediately after we have written it. At that point, it's still fresh in our memory, and we know exactly what the code is supposed to do.

Therefore, after we've created our new feature and confirmed it works as expected, we should review our code and see if we can improve it, before moving on.

In professional settings, this tends to be a required part of the process. We will ask other developers on the project to review our code and provide feedback before we merge it into the shared repository.

By restricting access to our classes in the way we did in the previous lesson, it also makes our code easier to refactor.

We know that other code is not going to be accessing the private parts of our class, so we are free to rewrite, delete and modify those as needed.

An Example

In the previous lesson, we might have left our class looking something like this:

class Monster {
public:
  void SetHealth(int NewHealth) {
    if (NewHealth <= 0) {
      Health = 0;
      isDead = true;
    } else {
      Health = NewHealth;
      isDead = false;
    }
  }

  bool GetIsDead() {
    return isDead;
  }

private:
  bool isDead { false };
  int Health { 150 };
};

A common first step to refactoring code is to ask ourselves if we can delete parts of it. For example, do we need to be storing and maintaining the private isDead boolean?

Because it's private, we know other code isn't accessing it - it's just being used in the GetIsDead function.

However, we can update that function to just use the Health value instead:

bool GetIsDead() {
  return Health <= 0;
}

Now, we can remove the isDead variable from our class entirely. With the variable gone, we no longer need to maintain it in the existing TakeDamage function, nor in any future function we create. This keeps our code clean and simple.

class Monster {
public:
  void SetHealth(int NewHealth) {
    if (NewHealth <= 0) {
      Health = 0;
      isDead = true; // not needed
    } else {
      Health = NewHealth;
      isDead = false;  // not needed
    }
  }

  bool GetIsDead() {
    return Health <= 0;
  }

private:
  bool isDead { false };  // not needed
  int Health { 150 };
};

Derived State

In the previous example, the issue is that we were storing unnecessary variables in our class. This is one of the most common ways projects become too complex.

The amount of code we need to write to keep all of our variables in a valid state gets out of hand.

If the value of a variable can be derived from the value of another variable, it is almost always better to replace that variable with a getter that performs the derivation, This is much easier to maintain than attempting to keep both variables synchronized, especially as our class gets more complex.

Test your Knowledge

Consider this function:

bool isEnraged() {
  bool isEnraged;
  if (Health <= 0) {
    isEnraged = false;
  } else if (Health <= 200) {
    isEnraged = true;
  } else {
    isEnraged = false;
  }
  return isEnraged;
}

Which of the following are ways to refactor it?

This lesson introduced refactoring in a very simple context - refactoring a simple function. But, it is the concept that is important. We should constantly be asking questions about our code - just because our solution worked, that doesn't mean it was a good solution.

C++ Class Constructors

Restricting the ability for external code to change properties like Health has introduced another limitation to our class.

It is no longer possible to initialise monsters with different Health values. Whilst allowing other code to modify the Health of monsters in an uncontrolled way was problematic, we might still want to provide the ability to choose the initial Health value for our monsters.

We already know enough to make this happen. We could, for example, create a public function on our class. We could call this function something like Initialise, and have it accept an argument for the initial health value.

We could even apply what we've learned to make sure this function is only called once per object:

class Monster {
public:
  void Initialise(int InitialHealth) {
    if (isInitialised) return;
    Health = InitialHealth;
    isInitialised = true;
  }

private:
  int Health { 150 };
  bool isInitialised { false };
};

But, so common is this requirement to set the initial values of class members, there is a special type of function specifically for this purpose. Constructors will be the topic of our next lesson!

Was this lesson useful?

Ryan McCombe
Ryan McCombe
Posted
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Classes
3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, unlimited access!

This course includes:

  • 66 Lessons
  • Over 200 Quiz Questions
  • Capstone Project
  • Regularly Updated
  • Help and FAQ
Next Lesson

Class Constructors

Learn about a special type of function we can add to our classes, which we can use to control how our objects get created.
3D art showing a blacksmith character
Contact|Privacy Policy|Terms of Use
Copyright © 2023 - All Rights Reserved