deleted functions (C++)
Learn deleted functions (C++) step by step with clear examples and exercises.
Why This Matters
In this full guide on Deleted Functions in C++, we delve into the importance and intricacies of these special member functions. Understanding deleted functions is crucial for mastering advanced C++ concepts, particularly when dealing with inheritance and polymorphism. This knowledge is indispensable for acing interviews, debugging real-world code, and writing robust, efficient programs.
Deleted functions help enforce compile-time type safety checks during inheritance, prevent users from calling specific functions on objects that don't make sense, ensure that derived classes cannot override functions that should not be overridden, and prevent inheritance of functions that are not meant to be inherited.
Prerequisites
Before diving into deleted functions, it's essential to have a solid grasp of the following topics:
- C++ Object-Oriented Programming (OOP) concepts
- Inheritance in C++
- Polymorphism in C++
- Function Overriding and Overloading
- Access Specifiers (public, protected, private)
- Virtual Functions
- Template Classes and Functions
- Understanding the difference between
virtualandoverridekeywords - Familiarity with C++ exceptions and error handling
- Understanding the concept of inheritance and polymorphism in C++
- Knowledge of function overloading and function overriding
- Understanding access specifiers (public, protected, private)
- Comprehension of virtual functions and their role in polymorphism
- Familiarity with the basics of C++ exceptions and error handling
Core Concept
What are Deleted Functions?
In C++, deleted functions are unique member functions that cannot be called or inherited. They are declared using the = delete syntax in the class declaration. When a deleted function is encountered during inheritance, it prevents the base class function from being used or overridden by derived classes.
Why use Deleted Functions?
Deleted functions help enforce compile-time type safety and prevent slicing. They are particularly useful when you want to:
- Prevent users from calling a specific function on an object that doesn't make sense (e.g., moving a dog by using a base class function)
- Ensure that derived classes cannot override a function that should not be overridden (e.g., a function that returns the number of legs for an animal, which should remain constant across all derived classes)
- Prevent inheritance of functions that are not meant to be inherited (e.g., private member functions)
- Enforce compile-time type safety checks during inheritance
Deleted Functions vs. Private Member Functions
While both deleted functions and private member functions can't be accessed outside their respective classes, there is a key difference:
- Private member functions are still part of the class and can be called by friend classes or functions. However, deleted functions cannot be called even by friend classes or functions.
- Deleted functions can be inherited (using
using Base::function;), while private member functions cannot.
Declaring Deleted Functions
To declare a function as deleted in a class, use the following syntax:
return_type function_name() = delete;
Or, if you want to prevent inheritance of a base class function, do this:
using Base::function; // Inherit the function from the base class
Base::function() = delete; // Declare it as deleted in the derived class
Worked Example
Let's consider an example where we have a base class Animal and derived classes Dog and Cat. We want to prevent users from creating a Dog or Cat object directly (since it doesn't make sense) and also prevent the creation of derived objects without specifying their concrete type.
#include <iostream>
class Animal {
public:
Animal() = default; // Default constructor to allow direct instantiation of Animal objects
virtual ~Animal() = default; // Default destructor to ensure proper memory deallocation
// Declare move() as deleted in the Animal class
void move() = delete;
};
class Dog : public Animal {
public:
Dog(const std::string& name) : name_(name) {}
std::string name_;
};
class Cat : public Animal {
public:
Cat(const std::string& name) : name_(name) {}
std::string name_;
};
int main() {
// Valid creation of Animal object since the default constructor is not deleted
Animal a;
// Attempt to create Dog or Cat objects results in compile-time errors
// as move() is declared as deleted in the base class Animal
Dog d(std::string("Rex")); // Compile Error: Animal::Dog(const std::string&) is deleted
Cat c(std::string("Whiskers")); // Compile Error: Animal::Cat(const std::string&) is deleted
}
Common Mistakes
- Not understanding the purpose of deleted functions: Deleted functions are not just for preventing function calls but also for enforcing type safety during inheritance.
- Declaring regular functions as deleted: Be careful when declaring functions as deleted, as they cannot be called or inherited even if it's intended.
- Not inheriting the base class function before deleting it: Inherit the base class function using
using Base::function;before declaring it as deleted to prevent ambiguity. - Using deleted functions inappropriately: Deleted functions should be used judiciously to maintain type safety and avoid unnecessary restrictions on derived classes.
- Not handling exceptions properly when calling a deleted function: If you call a deleted function within a try-catch block, the exception will not be caught since it is generated at compile-time.
- Attempting to inherit a deleted function from multiple base classes: When a derived class inherits a deleted function from multiple base classes, the function remains deleted in the derived class.
- Calling a deleted function through a pointer or reference of the base class: Attempting to call a deleted function through a pointer or reference of the base class results in a compile-time error.
- Not understanding the difference between
deleteanddelete[]:deleteis used for deleting individual objects, whiledelete[]is used for deleting arrays. - Attempting to delete a constructor or destructor: Constructors and destructors cannot be declared as deleted in C++.
- Not understanding the role of friend classes and functions with deleted functions: Friend classes and functions can still call deleted functions, but they cannot inherit or call them through an object of the class where the function is declared as deleted.
Practice Questions
- Given the following code, why does the compiler throw an error when trying to create a
Dogobject?
class Animal {
public:
virtual void move() = 0; // Pure virtual function
};
class Dog : public Animal {
public:
// Declare move() as deleted in the Dog class
using Animal::move;
void move() = delete;
};
int main() {
Dog d; // Compile Error
}
- Modify the
Animal,Dog, andCatexample to prevent the creation of derived objects without specifying their concrete type in the constructor call.
- Write a class hierarchy where you declare some functions as deleted to enforce type safety during inheritance.
- Implement a class
Shapewith base classesTwoDimensionalShapeandThreeDimensionalShape. Declare a functioncalculateArea()as deleted in theThreeDimensionalShapeclass, ensuring that derived classes cannot override it.
- Write a program that demonstrates the difference between using
deleteanddelete[]for deleting memory allocated dynamically.
FAQ
- What happens when a deleted function is called?: Attempting to call a deleted function results in a compile-time error.
- Can a deleted function be overridden in derived classes?: No, deleted functions cannot be overridden in derived classes.
- Is it possible to call a deleted function in friend classes or functions?: Yes, deleted functions can still be called by friend classes or functions. However, they cannot be inherited or called through an object of the class where the function is declared as deleted.
- Can a constructor be declared as deleted?: No, constructors cannot be declared as deleted in C++. However, you can declare default constructors as deleted to prevent direct instantiation of objects.
- What happens when a deleted function is inherited by a derived class?: The deleted function remains deleted in the derived class and cannot be called or overridden. If a derived class inherits a deleted function from multiple base classes, the function remains deleted in the derived class.
- Can a deleted function be virtual?: Yes, a deleted function can be declared as virtual. However, it cannot be called or inherited by any derived classes.
- What is the difference between
deleteanddelete[]?:deleteis used for deleting individual objects, whiledelete[]is used for deleting arrays. - Can a deleted function be a friend function?: Yes, a deleted function can still be declared as a friend function in another class or friend function declaration. However, it cannot be called through an object of the class where the function is declared as deleted.
- What happens when a deleted function is inherited from multiple base classes and overridden in a derived class?: If a derived class inherits a deleted function from multiple base classes and overrides it, the override will also be deleted in the derived class.
- Can a deleted function be used as a template argument?: No, a deleted function cannot be used as a template argument due to the requirement of a callable object for templates.