Table of content:
Static Data Member In C++ | Create, Access & More (+Code Examples)
A static data member in C++ is a class member that is shared among all instances of that class. Unlike regular data members, which have separate copies for each object of the class, a static data member is common to all objects of the class.
In this article, we'll explore the characteristics, usage, and benefits of static data members in C++. We’ll also cover practical examples and discuss how static members differ from other types of class members.
What Is Static Data Member In C++?
The static data member in C++ programming is a special type of class member that is associated with the class rather than with an individual object of a class. It means that all instances of the class share the same static data member. In other words, unlike regular (non-static members) data members, which have separate copies for each object, static data members are shared among all objects of the class.
Here are some key points you should note about the static data member in C++ programming language:
- Declaration of Static Data Member in C++: A static data member in C++ is declared using the static keyword within the class definition.
- Definition of Static Data Member in C++: The static data member in C++ must be defined outside the class (usually in the source file) to allocate memory for it. This is typically done by specifying the data type and the name of the static data member, along with its initial value (if any).
- Initialization of Static Data Member in C++: We can initialize a static data member in C++ programs using a constant expression or a compile-time constant. The initialization is done outside the class definition.
- Accessing a Static Data Member in C++: We must use the class name followed by the scope resolution operator(::) and the name of the respective static data member in C++ when we want to access it.
Here's a simple example to illustrate the concept of a static data member in C++:
Imagine there’s a car manufacturing firm that produces a variety of models of cars. Each of these models has its own max_speed property (i.e., data member). Now suppose the firm wants to keep a record of the total number of models manufactured by them.
- So they define a variable model_count, which is initialized once and is incremented from its past value by 1 unit every time a new model with its own max_speed property is launched.
- So, the firm can make this data member, model_count, a static data member such that its value is accessible on a class level and is shared by all the instances of that class.
How To Declare Static Data Members In C++?
The declaration of a static data member in C++ is done using the static keyword inside the class declaration. This is because they are linked to the class as a whole rather than to specific class objects. It indicates that the same static data member, which exists independently of any particular object, is shared by all class members' objects.
Although they have the advantage of being contained within the class scope, static data members are conceptually similar to global variables within the class. As a result, information within the class is more organized and contained.
Syntax to Declare a Static Data Member In C++:
class ClassName {
access_specifier:
static data_type data_member_name;
};
Here,
- The ClassName and data_member_name refer to the names of the class and the data member we are creating.
- An access_specifier indicates the visibility of the class member, which can be private, public or protected.
- The static keyword indicates that the respective member is of a static nature and the type of data it stores is given by data_type.
Let’s understand how to declare a static data member in C++ with the help of a sample code that showcases its implementation.
Code Example:
Output:
Total Mercedes models: 3
Code explanation:
In the above C++ program-
- We create a class named Mercedes with a static data member modelCount.
- The class also contains a constructor that increments the value of modelCount variable by 1 every time an object of the Mercedes class is created.
- Next, we initialize the static data member modelCount to 0, outside the class, using the scope resolution operator (::).
- In the main() function, we create three objects of the Mercedes class: m1, m2, and m3.
- Then, we access the modelCount static data member using the class name and variable name (i.e., Mercedes::modelCount).
- This allows us to retrieve the total count of Mercedes models created so far, which is printed to the console using cout.
How To Initialize/ Define Static Data Member In C++?
After you declare a static data member in the class definition, it's time to define it outside the class definition. Typically, this is done in the implementation file (.cpp) associated with the class. The definition provides the memory allocation and initialization for the static data member.
Are you wondering why defining the data member outside the class definition is necessary? We must define (or initialize) the static data members outside the class definition for two main reasons. They are:
1. Multiple Definition Error
Since all instances of a class share static data members, defining the static data member inside a C++ class might cause issues if multiple translation units (those .cpp files) are included in the class definition.
- Imagine the linker's dilemma when it tries to merge these object files into an executable. (The linker is an essential component of the software development process, specifically in the compilation of programs written in languages like C and C++. It plays a crucial role in creating the final executable file from multiple object files generated during the compilation).
- It finds multiple definitions of the same static data member lurking around, causing confusion.
- As a result, the linker presents us with that dreaded multiple-definition error.
So, defining a static data member outside the C++ class helps us avoid a situation where the program gets confused about which definition to use. It keeps things organized and allows the linker to do its job smoothly.
2. External Linkage
The static data member in C++ has a special property known as external linkage. This means that they can be accessed from other translation units (other .cpp files) in our program. However, if we define static data members inside the class, they will have internal linkage limiting their accessibility to only within the class itself.
- In simpler terms, when we define a static data member in C++ programs inside the class, it becomes like a private secret that only the class itself can access.
- But if we define it outside the class, it becomes a shared resource that other parts of our program can also access and use.
The syntax to define a static data member in C++ outside of a class definition is:
class ClassName {
public:
static data_type data_member_name;
};
data_type ClassName::data_member_name = some_initial_value;
Here, the syntax for declaration of static data member in C++ class remains the same, we just add a line of initialization outside the class definition. We use the scope resolution operator (::) to access the respective data member declared inside the class and assign the initial value given by some_inital_value.
Defining Static Data Member In C++ Using Const Keyword (Inside The Class)
While generally, we should not define a static data member inside the class, there is one exception to this. A static data member that is being created as a constant can be initialized/ defined inside the class definition itself.
When a data member is declared as static const, it means it is a constant value shared by the entire class, i.e., among all instances of the class and cannot be modified. Look at the syntax and the C++ code example below to see how this is done.
Syntax:
class ClassName {
public:
static const dataType staticConstantMemberName = initial value;
};
Here, the const keyword indicates that the static data member/ variable is constant and cannot be modified. The syntax for declaration of the constant static data member in C++ classes remains the same however, we can initialize it inside the class.
Code Example:
Output:
Static constant value: 42
Static constant value (via function): 42
Explanation:
- We create a class MyClass and declare a public static data member myStaticConstant.
- Since we are using the const keyword in the definition, it means the data member is constant and static. So, we initialize it with the value 42 inside the class definition.
- Next, we define a static member function getStaticConstant(), which simply returns the value of the static constant member variable myStaticConstant.
- In the main() function, we access the static constant data member twice. In the first case, we use the class name with the static data member name and scope resolution operator.
- In the second case, we call the static member function using the scope resolution operator.
- We print the outcome of both cases using cout commands.
- When we print the value of MyClass::myStaticConstant, it will output 42, which is the value of the static constant member variable.
- When we call MyClass::getStaticConstant(), it returns the same value, 42, and the output will be Static constant value (via function): 42.
- This shows that we can initialize a constant static data member inside the class and access it the same as any other static data member.
Ways To Access A Static Data Member In C++
As mentioned before, a static data member in C++ belongs to the class as a whole and not the individual objects or instances of the class. This means all the objects/ instances of the class share the same static data member, which can be accessed in two different ways. One method involves directly using the class name with the scope resolution operator, and the other involves using the member functions.
We have discussed these ways of accessing a static data member in C++ in the sections ahead, along with examples for a better understanding.
How To Access Static Members Without An Object (Using Class Name)?
Since static members are associated with the class itself and not with individual objects, you can access a static data member in C++ without creating an object of the class. For this, you must use the name of the respective class followed by the scope resolution operator (::) and then the name of the static data member. This is a fundamental characteristic of static data members in C++.
Look at the sample C++ program ahead to understand how to actually access a static data member without creating an object or using one.
Code Example:
Output:
Static Value: 42
This is a static function.
Explanation:
In the code above,
- We first define a class named MyClass and declare a static data member staticValue of type int. This static data member is shared among all instances of the class.
- Next, we initialize the static data member staticValue outside the class definition, assigning it the value 42. This step is necessary because static data members must be defined outside the class to allocate memory.
- In the main() function, we access the static member directly using the class name MyClass and the scope resolution operator (::). We print the value of staticValue to the console, which outputs 42.
- Since static members are shared and do not require an instance of the class to be accessed, we do not need to create an object of MyClass to access staticValue.
- Finally, the main function() returns 0, indicating successful completion.
How To Access Static Data Member In C++ Using Static Member Function?
In C++, you can also access static data members using a static member function. We will discuss the concept of a static member function in the next section. First, let's look at how to use it to access a static data member in C++ programs. For this, we must use the scope resolution operator along with the class name to call the respective static member function.
Here's an example demonstrating how to access a static data member in C++ using a static member function.
Code Example:
Output:
Value of Static Data Member: 101
Explanation:
In the above code example-
- We define a class called MyClass and declare a static data member staticValue of type int. This static member is shared across all instances of the class.
- We also declare a static member function getStaticValue() within the class. This function returns the value of the static data member staticValue.
- Outside the class, we initialize the static data member staticValue to 101. This initialization is necessary because static members must be defined outside the class to allocate storage.
- In the main() function, we call the static member function getStaticValue() using the class name MyClass and the scope resolution operator (::). This function call retrieves the value of staticValue, which is 101.
- We finally store the returned value in an integer variable value and print it to the console.
What Are Static Member Functions In C++?
Static member functions in C++ are special functions associated with a class that belongs to the class itself rather than to any specific object of the class, unlike the non-static member function. This type of member function is declared using the static keyword, just like static data members.
Syntax for Static Member Function in C++:
class ClassName {
static return_type staticFunction(list of arguments) {
// This function is a static member function.
// It does not need to be called with an object of the ClassName class.
}
};
Here,
- The static keyword indicates that the function is a static member function. This means the function belongs to the class itself, not to any specific object of that class.
- The return_type refers to the type of value the function will return.
- The list of arguments refers to the arguments accepted by the member function.
Read More: Static Member Function In C++ Explained With Proper Examples
Example Of Member Function & Static Data Member In C++
In this code example, we illustrate how static data members and member functions work in C++. We will create multiple instances of the Mercedes class, each with a unique model ID and maximum speed, while using a static member to keep track of the total number of models produced.
Code Example:
Output:
Model ID: 1, Max Speed: 250 km/h
Model ID: 2, Max Speed: 300 km/h
Model ID: 3, Max Speed: 200 km/h
Code Explanation:
In the above code example:
- We start by defining a class called Mercedes to represent different car models.
- Within this class, we declare a static data member, modelCount, to keep track of the total number of models produced. This static variable is shared across all instances.
- We also declare two non-static data members: modelID and maxSpeed. The modelID gives each model a unique identifier, while maxSpeed stores the maximum speed for each model. These are unique to each object.
- The class has a constructor that takes an integer speed and initializes maxSpeed. It also increments modelCount and assigns the updated value to modelID, ensuring each model gets a unique ID.
- The display() function, marked as const, outputs the modelID and maxSpeed of the object, showing each model’s unique identifier and speed.
- Outside the class, we define and initialize modelCount to 0, setting up the initial state for counting models.
- In the main() function, we create instances of the Mercedes class, each with a specified maxSpeed. We then call display() on each instance to print their details, verifying the correct assignment of modelID and maxSpeed.
Practical Applications Of Static Data Member In C++
Static data members in C++ have several practical applications, including:
-
Shared Resource Tracking: We can use static data members to keep track of resources shared across all instances of a class, such as counting the number of objects created or managing a shared connection pool.
-
Global Configuration: Static data members in C++ programs allow us to store configuration settings or constants that need to be consistent across all instances, like a global logging level or application settings.
-
Memory Efficiency: Static data members reduce memory usage by sharing data among all objects. This is particularly useful when the data is the same across all instances, such as a class-wide lookup table or cache.
-
Counting: Counting or tracking the frequency of events/ specific operations is a tedious, repetitive task prevalent across industries and operations. Creating a class and using the concept of static data member in C++ can automate and hence simplify tasks such as tracking function calls, object creations, or error occurrences.
-
Storing constants: Static data members in C++ are ideal for storing constants that are shared by all objects of a class. In software development, constants are frequently used to define standardized values, such as conversion factors, maximum limits, or default settings.
Tips To Use Static Data Member In C++
Here are some tips for effectively using static data member in C++ classes:
-
Use for Shared Data: We should use static data member in C++ when we need data that is shared across all instances of a class, such as counters, configuration settings, or shared resources.
-
Initialize Carefully: Static data member in C++ must be initialized outside the class definition, typically in a .cpp file. It is done to avoid multiple definitions and to ensure proper initialization before use. This will help to prevent errors throughout your entire program.
-
Control Access: Consider using private or protected access for static data members, providing public static member functions to control how the data is accessed or modified, ensuring encapsulation and data integrity.
-
Avoid Overuse: While static data members are useful, overusing them can lead to tight coupling and reduced flexibility. We should reserve them for situations where shared state is truly necessary.
-
Thread Safety: In multithreaded applications, be mindful of thread safety when using static data members. We might need to use synchronization mechanisms like mutexes to avoid race conditions.
Conclusion
We now know that a static data member in C++ is a class member that is declared using the static keyword. There is only one copy of a static data member, regardless of how many objects of the class are created.
- A static data member in C++ can be accessed from anywhere in the program, even from outside the class, and can be used to store constants, counters, and other data that is shared by all objects of the class.
- The static data member in C++ programs is stored in the static storage duration, which means that it is allocated when the program starts and deallocated when the program ends.
- Since a static data member in C++ is not attached to a specific object, it cannot cannot be accessed using the 'this' pointer.
- Static data member can be declared const, in which case it cannot be modified after they are initialized.
Frequently Asked Questions
Q. Is there any difference between const static data_type variable_name and static const data_type variable_name?
No, there is no difference between the two. The C++ programming language allows flexibility in the placement of the const and static keywords in declarations, allowing programmers to choose a style that they find more readable or consistent with their coding conventions. The placement of the const and static keywords does not affect the behavior or meaning of the variable_name. Both declarations achieve the same result, which is to define a constant static data member in C++ programs.
Q. Can a static data member be inherited by derived classes?
Yes, a static data member in C++ base class can be inherited by derived classes. When a derived class is derived from a base class that has static data members, the derived class inherits those static data members along with other members of the base class.
Let’s understand it with an example program:
Output :
Total Mercedes Models: 3
Explanation:
In this code snippet, we define a Mercedes class with a static data member totalModels that tracks the total number of Mercedes objects created.
Each time we create a new object, totalModels is incremented, and we can use a static function to display this count.
The maxSpeed member is unique to each object, representing the maximum speed of that specific model.
Q. What are the differences between const and static data members in C++?
A const data member is a member variable that cannot be modified after it has been initialized, whereas a static data member is a member variable that is shared among all instances of the class. Below is a tabular representation of the differences between the constant and the static data member in C++.
Here's a table comparing const and static data members in C++:
Aspect | const Data Member | static Data Member |
---|---|---|
Memory Allocation | Allocated separately for each object instance. | Shared among all instances of the class (single copy). |
Initialization | Must be initialized at the point of declaration inside the class (usually in the constructor). | Initialized outside the class definition. |
Access | Accessed through an object instance. | Can be accessed using the class name (without an object). |
Mutability | Immutable after initialization; cannot be changed. | Can be modified (if not declared as const). |
Lifetime | Lifetime tied to the object's lifetime. | Lifetime tied to the program's duration (static storage duration). |
Use Case | Used for values that should not change after being set, typically unique for each instance. | Used for values shared among all instances, often for counters or shared settings. |
Storage Class | const specifies immutability, not storage class. | static is a storage class specifier indicating shared memory. |
Combination with const | Cannot combine with static in the same data member. | Can be combined with const to create a shared, constant value. |
Example | const int maxAge = 100; inside a constructor. | static int count; declared in the class and defined outside. |
Q. What are the differences between const and constexpr?
In C++, both const and constexpr are used to define variables that are defined as constant and cannot be modified once initialized. However, there are a few key differences between the two, as mentioned in the table below:
Parameters |
Constant (const) |
Constant Expression (constexpr) |
Value Determination |
Determined at runtime |
Determined at compile-time |
Usage |
Any class variable (local, global, member) |
Primarily for constants and template arguments |
Expression Complexity |
Can be complex expressions or function calls |
Limited to constant expressions |
Context Dependency |
They can depend on runtime values |
Cannot depend on runtime values |
Compile-time Error |
Invalid value assignment generates a compile-time error |
Invalid value assignment generates a compile-time error |
Q. How is synchronization achieved when multiple threads access a static data member in C++?
Synchronization is essential when multiple threads access a static data member in C++ to ensure that the data remains consistent and prevent potential race conditions. A race condition occurs when two or more threads access a shared resource simultaneously, leading to unpredictable behavior and incorrect results. You can use various synchronization mechanisms to protect access to the static data member in C++, such as:
- Mutex (std::mutex): Mutex stands for mutual exclusion. It is a synchronization primitive that allows only one thread to access the protected data at a time.
- Before accessing the static data member, a thread must lock the mutex. If another thread has already locked the mutex, the requesting thread will be blocked until the other thread releases the mutex.
- Once the thread finishes its operation on the static data member, it must unlock the mutex, allowing other threads to access the data.
- Reader-Writer Locks (std::shared_mutex): Reader-writer locks allow multiple threads to read the static data simultaneously but ensure that only one thread can write to the data at any given time.
- Multiple threads can acquire a shared (read) lock, allowing concurrent access for reading.
- However, when a thread acquires an exclusive (write) lock, it prevents other threads from reading or writing until the write operation is complete.
- Atomic Operations (std::atomic): When dealing with simple data types (e.g., integer or enumeration type), atomic operations can be used to ensure that the access and modification of the static data member are atomic (indivisible). Atomic operations guarantee that a read or write operation is completed without interruption from other threads.
- Critical Sections (platform-specific): Some platforms provide specific functions or APIs to create critical sections, which act similarly to mutexes. Critical sections protect code regions, ensuring that only one thread executes the critical section at a time.
Using any of these mechanisms can help ensure synchronization when working with a static data member in C++.
Here are a few other interesting topics you must know about:
- C++ Type Conversion & Type Casting Demystified (With Examples)
- Pointers in C++ | A Roadmap To All Types Of Pointers With Examples
- Inline Function In C++ | Declare, Working, Examples & More!
- References In C++ | Declare, Types, Properties & More (+Examples)
- Array In C++ | Ultimate Guide On Creation, Types & More (Examples)