Why do we need to disable C++ constructors?

Key takeaways:

  • Disabling constructors is a valuable design technique in C++ that serves various purposes and ensures the following:

    • Ensures only one instance of a class exists, accessible via a static method.

    • Prevents instantiation of classes that contain only static methods.

    • Maintains object state by preventing modifications after construction.

    • Prevents class behavior by disallowing subclassing.

Constructor is a special type of member function that is called when an object of a class is created. It is used to initialize the object's state. However, there are times when we might want to prevent the creation of objects of a class. This is where disabling constructors come into play.

Why disable constructors

  1. Singleton pattern: To ensure that only one instance of a class exists.

  2. Static utility classes: To prevent instantiation of utility classes that only contain static methods.

  3. Immutable classes: To prevent modification of objects after construction, ensuring their state remains constant.

  4. Preventing inheritance: To ensure the class should not be used as a base class for other classes.

Implementation examples

Let's explore the some implementations to disable the constructor:

Example 1: Singleton pattern

This can be useful when we want to ensure that only one instance of a class is created.

Let's take an example of Singleton a class that has a private constructor. The getInstance method provides a way to access a single instance of the class. The value member variable is used to demonstrate that the same instance is being accessed and modified across different parts of the code:

#include <iostream>
class Singleton {
public:
// Static method to get the instance of Singleton
static Singleton& getInstance() {
// Guaranteed to be destroyed.
// Instantiated on first use.
static Singleton instance;
return instance;
}
// Other public member functions
void setValue(int value) {
this->value = value;
}
int getValue() {
return value;
}
private:
// Private constructor to prevent instantiation
Singleton() : value(0) {}
// Private destructor to prevent deletion
~Singleton() {}
// Private copy constructor and assignment operator to prevent cloning and assignment
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
int value;
};
int main() {
// Trying to create an instance of Singleton will result in a compile-time error
// Singleton singletonInstance; // Error: constructor Singleton() is private
// Get the instance of Singleton
Singleton& singleton = Singleton::getInstance();
// Set and get the value
singleton.setValue(42);
std::cout << "Value: " << singleton.getValue() << std::endl;
return 0;
}

Code explanation

  • Lines 6–11: The single instance of the Singleton class is created on the first call getInstance() and is destroyed automatically when the program exits.

  • Lines 14–20: These methods allow setting and getting the value of the Singleton instance.

  • Line 38: We create an instance of Singleton will result in a compile-time error due to the private constructor.

  • Line 41: We call the getInstance() to get a reference to the Singleton instance.

  • Line 44: We set the value of the Singleton instance to 42 using setValue(42).

  • Line 45: We print the value of the Singleton instance using getValue().

Example 2: Final class

Preventing inheritance is used when we want to design a class that should not be used as a base class for other classes. This can help maintain the integrity of the class's design and prevent unintended behavior that could arise from subclassing.

Let's take an example of a Product class representing a generic product. We want to create a FinalProduct class for products that are ready for sale. We want to prevent any further subclassing of FinalProduct to maintain the consistency of the final product's behavior and attributes:

#include <iostream>
class Product {
public:
Product(const std::string& name) : name(name) {}
virtual void assemble() {
std::cout << "Assembling " << name << std::endl;
}
virtual void package() {
std::cout << "Packaging " << name << std::endl;
}
protected:
std::string name;
};
class FinalProduct final : public Product {
public:
FinalProduct(const std::string& name, double price) : Product(name), price(price) {}
void sell() {
std::cout << "Selling " << name << " for $" << price << std::endl;
}
private:
double price;
};
// Trying to create a subclass of FinalProduct will result in a compile-time error
// class SubFinalProduct : public FinalProduct {}; // Error: 'SubFinalProduct' declared as final
int main() {
FinalProduct product("Smartphone", 999.99);
product.assemble();
product.package();
product.sell();
return 0;
}

Code explanation

  • Line 5: A product class constructor takes a parameter name and initializes the name member variable.

  • Lines 7–9: A virtual method assemble() that prints "Assembling" with the name of the product.

  • Line 11–13: A virtual method package() that prints "Packaging" with the name of the product.

  • Line 21: A constructor that takes a parameter name and a price, and initializes the base class Product with name and it's own price member variable.

  • Line 23–25: A sell() Method that prints "Selling" followed by the name of the product and its price.

  • Line 35: Creates an instance FinalProduct called product with the name "Smartphone" and a price of 999.99.

  • Line 36–38: Call the assemble(), package(), and sell() methods on the product object to show the functionality of the class hierarchy.

Disabling constructors is a valuable design technique in C++ that serves various purposes, from enforcing the singleton pattern to maintaining immutability and preventing unintended inheritance. By strategically disabling constructors, developers can create more robust, maintainable, and predictable code, ensuring that classes are used as intended and safeguarding against common pitfalls in object-oriented programming.

Frequently asked questions

Haven’t found what you were looking for? Contact Us


Why do we use copy constructor in C++?

A copy constructor is a method of a class which initializes an object using another object of the same class. A copy constructor can be called in various scenarios. For example:

  • In the case where an object of a class is returned by value.
  • In the case of an object of a class being passed, by value, ​to a function as an argument.

Is constructor mandatory in C++?

No, a constructor is not mandatory in C++. If no constructors are defined, the compiler provides a default constructor automatically.


Why do we use move constructor in C++?

A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy.

An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved