Follow our official account to keep receiving embedded knowledge!
1. Comparison of Object-Oriented and Procedure-Oriented Programming
Imagine you want to build a house.
-
Procedure-Oriented: It’s like you are doing everything yourself. Your thinking is linear: “First, I will move bricks -> then mix cement -> next, build walls -> finally, put on the roof.” You focus on the steps, which are actions (verbs). Writing code is like writing a recipe, detailing what to do first, second, and so on.
// Procedure-oriented C-style code example: Cooking a meal void washVegetables() { /* Wash vegetables */ } void cutVegetables() { /* Cut vegetables */ } void cook() { /* Cook vegetables */ } int main() { washVegetables(); // Step 1: Wash cutVegetables(); // Step 2: Cut cook(); // Step 3: Cook return 0; } -
Object-Oriented: It’s like you are an architect or a foreman. Your thinking is to first design the blueprint, then organize the work. You would first think: “I need a house, which consists of doors, windows, walls, and a roof.” Here, “house,” “door,” and “window” are objects. You focus on things, which are nouns, and what functions (methods) these things have.
// Object-oriented C++ style code example: Organizing a meal class Chef { // 1. First, design a "Chef" blueprint public: void washVegetables() { /* Chef can wash vegetables */ } void cutVegetables() { /* Chef can cut vegetables */ } void cook() { /* Chef can cook */ } }; int main() { Chef chefWang; // 2. Based on the blueprint, hire a chef named chefWang (create an object) // 3. Direct the chef to do tasks (call object methods) chefWang.washVegetables(); chefWang.cutVegetables(); chefWang.cook(); return 0; }
Core Differences:
- Procedure-Oriented: Focuses on steps, doing it yourself.
- Object-Oriented: Focuses on things, directing others (objects) to do it. Code is more modular, easier to maintain and reuse, like LEGO blocks, where each part (object) has its own role.
To better understand the workflow differences between the two, see the flowchart below:

2. Preliminary Understanding of C++ Classes
“Class” is the core concept of object-oriented programming. The “Chef blueprint” mentioned earlier is a class. Let’s use another analogy:
-
Class: It’s like the design blueprint of a car. The blueprint specifies that the car should have:
- Attributes: For example, color, brand, maximum speed. These are nouns, referred to as member variables in the class.
- Behaviors: For example, accelerating, braking, honking. These are verbs, referred to as member functions in the class.
-
Object: It is a real car manufactured based on that design blueprint. From one blueprint, thousands of real cars can be produced.
Let’s draw a design blueprint for a “Dog” using code:
#include <iostream>
#include <string>
using namespace std; // To simplify the code, we tell the compiler we are using the standard namespace
// 1. Draw a design blueprint for a "Dog" (define a class)
class Dog {
// Typically, attributes are set to private, like locked in a cage, to protect them from being modified arbitrarily. This will be explained in detail later.
private:
string name; // Dog's name (member variable)
int age; // Dog's age (member variable)
// Typically, behaviors are set to public, like a public interface, accessible to anyone.
public:
// 2. Dog's behaviors (member functions)
void setName(string dogName) { // Method to name the dog
name = dogName;
}
void setAge(int dogAge) { // Method to set the dog's age
age = dogAge;
}
void bark() { // Method for the dog to bark
cout << name << " says: Wang Wang! I'm " << age << " years old." << endl;
// cout can be understood as "print to the screen", endl is a newline.
// << can be imagined as "sending the content over".
}
};
int main() {
// 3. Manufacture a real dog based on the blueprint (create an object)
Dog myDog;
// 4. Direct my dog to do tasks (call object methods)
myDog.setName("Wang Cai"); // Name my dog "Wang Cai"
myDog.setAge(2); // Set its age to 2 years
myDog.bark(); // Let my dog bark
return 0;
}
Output:
Wang Cai says: Wang Wang! I'm 2 years old.
See, we don’t need to care about how the <span>bark()</span> function is implemented internally; we just need to know the behavior of “let the dog bark.” This is called encapsulation: hiding complex implementation details and exposing only simple usage interfaces.
Next, we will use a class diagram to visually represent the design of the <span>Dog</span> class:

Illustration: <span>Dog</span> class encapsulates data (name, age) as private (-) and only provides public (+) methods for interaction.
3. Analysis of the this Pointer
Now there’s a question: In a class member function, what if the parameter name is the same as the member variable name? For example:
void setName(string name) {
name = name; // Which name is the parameter? Which name is the member variable? It's unclear!
}
This is like being in a room where there is a big horn (member variable), and you are holding a small horn (parameter). When you say “horn, start shouting,” how does anyone know which horn you mean?
To solve this problem, C++ provides a secret weapon called the <span>this</span> pointer.
<span>this</span>pointer: It can be understood as the object’s own “ID card” or “self-pointer.” Inside any member function, the<span>this</span>pointer silently points to the object that calls this function.
We can use <span>this</span><span> to modify the above code:</span>
class Dog {
private:
string name;
int age;
public:
void setName(string name) { // Parameter name and member variable name can be the same
this->name = name; // this->name refers to "my own name",
// the name on the right side of the equals is the passed parameter.
// This is like saying: "My name (this->name) = the new name you passed (name)"
}
void setAge(int age) {
this->age = age; // "My age = the new age you passed"
}
void bark() {
// Even if not used here, the this pointer exists, it can be written as:
// cout << this->name << " says: Wang Wang!" << endl;
cout << name << " says: Wang Wang!" << endl; // Usually, name implies this->
}
};
Remember this in one sentence:<span>this</span> is like the “I” in every object, it always points to itself. When there is a name conflict, use <span>this-></span> to clearly indicate “my own variable.”
4. Destructor and Constructor
Now let’s learn about two special functions: the object’s “birth certificate” and “will.”
Constructor
- What it is: A special member function that is automatically called when an object is created.
- Its role: To initialize the object, assigning initial values to the object’s member variables. Just like when a child is born, the doctor registers the birth date, weight, and height.
- Its characteristics:
- The function name is exactly the same as the class name.
- It has no return type (not even
<span>void</span>).
Destructor
- What it is: A special member function that is automatically called when an object is destroyed.
- Its role: To clean up, such as releasing memory allocated during the object’s lifecycle, closing open files, etc. Just like a person writing a will before passing away to handle their assets.
- Its characteristics:
- The function name has a tilde (~) added before the class name.
- It has no return type, and also no parameters.
#include <iostream>
using namespace std;
class Dog {
private:
string name;
int* ptr; // A pointer to demonstrate the role of the destructor
public:
// 1. Constructor (can be overloaded, multiple versions)
Dog() { // Default constructor (no parameters)
name = "Unnamed";
ptr = new int(0); // Dynamically allocate memory when the object is created
cout << "A dog named \"" << name << "\" is born! (Default Constructor)" << endl;
}
Dog(string name, int age) { // Parameterized constructor
this->name = name;
ptr = new int(age); // Allocate memory and initialize with age value
cout << "A dog named \"" << name << "\" is born! (Parameterized Constructor)" << endl;
}
// 2. Destructor (only one, no parameters)
~Dog() {
delete ptr; // Release previously allocated memory when the object is destroyed to prevent memory leaks
cout << "The dog named \"" << name << "\" says goodbye... (Destructor)" << endl;
}
void bark() {
cout << name << " says: Wang Wang! I'm " << *ptr << " years old." << endl;
}
};
int main() {
cout << "Start of main" << endl;
{ // A new scope begins
Dog dog1; // Calls the default constructor, dog1 is born!
Dog dog2("Buddy", 3); // Calls the parameterized constructor, dog2 is born!
dog1.bark();
dog2.bark();
} // Scope ends, dog1 and dog2's lifecycle ends, their destructors will be automatically called!
cout << "End of main" << endl;
return 0;
}
Output:
Start of main
A dog named "Unnamed" is born! (Default Constructor)
A dog named "Buddy" is born! (Parameterized Constructor)
Unnamed says: Wang Wang! I'm 0 years old.
Buddy says: Wang Wang! I'm 3 years old.
The dog named "Buddy" says goodbye... (Destructor)
The dog named "Unnamed" says goodbye... (Destructor)
End of main
Note the order of destructor calls: The last created object (<span>dog2</span>) is destroyed first, the destructor is called first, just like demolishing a house from top to bottom.
5. const Members
<span>const</span> is short for “constant,” meaning “unchangeable.” It has two main uses:
1. const Object (Constant Object)
It’s like you bought a “non-modifiable protective cover” for the object, declaring that this object itself is constant and cannot be modified.
const Dog myDog("Lucky", 5); // Create a constant dog named Lucky
// myDog.setName("Not Lucky"); // Error! Constant objects cannot call functions that may modify their content!
myDog.bark(); // If bark() guarantees not to modify the object, it can be called
This leads to the next question: How can the <span>bark()</span> function assure the compiler that it will not modify the object?
2. const Member Function (Constant Member Function)
By adding the <span>const</span> keyword after the member function’s parameter list, this function becomes a constant member function. It promises the compiler and users: “I will never modify any member variables in this object.”
class Dog {
// ... other members as above ...
// Constant member function: promises not to modify the object state
void bark() const { // Note the const after the function declaration
// this->age = 10; // Error! Cannot modify member variables in const member functions!
cout << name << " says: Wang Wang! (I promise I won't change anything!)" << endl;
}
// Non-const member function: allows modification of the object
void haveBirthday() {
(*ptr)++; // Increase age by 1
}
};
int main() {
const Dog lucky("Lucky", 5); // Constant object
lucky.bark(); // Correct: bark() is a const function, can be called by constant objects
// lucky.haveBirthday(); // Error! haveBirthday() is not a const function, constant objects cannot call it
Dog regularDog("Regular", 2); // Non-constant object
regularDog.bark(); // Correct: Non-constant objects can call const functions
regularDog.haveBirthday(); // Correct: Non-constant objects can also call non-const functions
return 0;
}
Life Metaphor::
<span>const Object</span>is like a museum exhibit covered with glass, only to be viewed, not touched.<span>const Member Function</span>is like a “read-only” guide next to the exhibit, who will only explain (read data) and will never touch or change the exhibit (write data).
6. static Members
<span>static</span> means “static.” A class’s <span>static</span> members (variables or functions) have a very special property: they do not belong to any specific object, but belong to the entire class.
- Static Member Variables: A variable shared by all objects, like a public class fund, which does not belong to any student, but every student can know and use it.
- Static Member Functions: Functions that can only operate on static member variables. Like a class life committee member, who only manages the class fund (static variable), not any student’s private pocket money (ordinary member variable).
#include <iostream>
using namespace std;
class Dog {
private:
string name;
// Static member variable: records how many dogs have been created (does not belong to any dog, belongs to the Dog class itself)
static int count; // Only declared within the class, needs to be defined and initialized outside the class
public:
Dog(string n) : name(n) {
count++; // Each time a dog is created, the counter increases by 1
cout << name << " joined! Total dogs: " << count << endl;
}
~Dog() {
count--; // Each time a dog disappears, the counter decreases by 1
cout << name << " left! Total dogs: " << count << endl;
}
// Static member function: it has no this pointer because it does not belong to a specific object
static int getCount() {
// cout << name; // Error! Static functions cannot access ordinary non-static member variables (name)
return count; // Correct! Static functions can access static member variables
}
};
// Define and initialize the static member variable outside the class (very important!)
int Dog::count = 0; // "::" is the scope resolution operator, meaning "count in the Dog class"
int main() {
cout << "Initial dog count: " << Dog::getCount() << endl; // Access static function directly through class name
Dog* dog1 = new Dog("Wang Cai");
cout << "Now, total dogs: " << Dog::getCount() << endl; // Output: 1
{
Dog dog2("Xiao Bai");
cout << "Now, total dogs: " << Dog::getCount() << endl; // Output: 2
// Static functions can also be accessed through objects, but they belong to the class, not to the object
cout << "Same count, accessed by dog2: " << dog2.getCount() << endl; // Output: 2
} // dog2 destructor, count decreases by 1
cout << "After Xiao Bai left: " << Dog::getCount() << endl; // Output: 1
delete dog1;
cout << "Final dog count: " << Dog::getCount() << endl; // Output: 0
return 0;
}
**Remember <span>static</span>**: It is the class’s “public property” and “public service,” unrelated to specific objects.
7. Friends
In C++, a class’s <span>private</span> and <span>protected</span> members are protected, and external functions and functions from other classes cannot access them. This is like your private bedroom, which outsiders cannot enter.
However, sometimes you may want your best friend to have special access to your bedroom. <span>friend</span> (friend) is this “exception.”
- Friend Function: A non-member function (ordinary function) granted access to a class’s private members.
- Friend Class: All member functions of a class are granted access to another class’s private members.
Note: Friend relationships are one-way and do not have transitivity (your friend’s friend is not your friend). Use friends cautiously, as they break encapsulation.
#include <iostream>
using namespace std;
// Forward declare Dog class so that Friend function knows it exists
class Dog;
// A global function (non-member function)
void friendFunction(const Dog& d);
class Dog {
private:
string secret; // Dog's secret, private member
public:
Dog() : secret("I hid my bone under the tree!") {} // Initialize secret
// Declare friend function! Note, this declaration is saying: "friendFunction is my friend, let it into my private room!"
friend void friendFunction(const Dog& d);
};
// Implement friend function
void friendFunction(const Dog& d) {
// Because this function is a friend of Dog class, it can access Dog's private member secret
cout << "The dog tells me a secret: \"" << d.secret << "\"" << endl;
// If it were not a friend, this line would cause an error: cannot access private member
}
int main() {
Dog myDog;
// myDog.secret; // Error! main function is not a friend, cannot access private member.
friendFunction(myDog); // Correct! Friend function can access.
return 0;
}
Output:
The dog tells me a secret: "I hid my bone under the tree!"
Friend Metaphor:: Just like in a company, all employees’ salaries are confidential (<span>private</span>), but the HR manager needs to view everyone’s salaries, so the HR manager can be set as a <span>friend</span> of all employees. However, ordinary employees cannot view each other’s salaries.
Summary
Alright, today we used a lot of metaphors and simple code to learn the most basic concepts of C++ object-oriented programming. Let’s review:
| Concept | Chinese | Core Metaphor |
|---|---|---|
| Class & Object | 类与对象 | Design Blueprint vs Real Product |
| this pointer | this指针 | Object’s ID Card / “I” |
| Constructor/Destructor | 构造函数/析构函数 | Birth Certificate / Will |
| const Member | const成员 | Exhibit under Glass / Read-Only Guide |
| static Member | static成员 | Public Class Fund / Life Committee Member |
| friend | 友元 | Best Friend (Privilege) |
The essence of object-oriented programming is: to bundle data and methods that operate on that data together into an “object,” and then complete complex programs through interactions between objects. This aligns more closely with our human understanding of the real world.
Recommended for You:
Data-Driven Programming: Make Your Embedded Code More Elegant!
Lightweight Communication Protocols for Embedded Systems!
Lightweight Circular Buffer Management Library for Embedded Systems!