function specifiers modify the behavior of functions. They can influence when and how the function is called, whether it can be overridden, and how it handles optimization or linkage.
1. inline
- Purpose: Suggests to the compiler to replace a function call with the actual code of the function to reduce overhead from the call itself.
- Use Case: Used for small, frequently called functions to eliminate the function call overhead, especially when performance is critical.
- Example
inline int square(int x) {
return x * x;
}
Note: This is a request to the compiler, not a command. Modern compilers often decide on inlining based on optimization strategies.
2. virtual
(C++ only)
- Purpose: Allows a function in a base class to be overridden in derived classes, enabling polymorphism.
- Use Case: Enables runtime (dynamic) method dispatch. If a function is declared as
virtual
, C++ will determine which function to call at runtime based on the object type, rather than the pointer or reference type. - Example:
class Base {
public:
virtual void display() {
std::cout << "Base class display function\n";
}
};
class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display function\n";
}
};
Note: If a function is not declared virtual
, C++ uses static binding, meaning the function is determined at compile-time.
3. explicit
(C++ only)
- Purpose: Prevents the compiler from using a constructor for implicit type conversions.
- Use Case: Used with constructors that take a single argument to prevent unexpected type conversions.
- Example:
class MyClass {
public:
explicit MyClass(int value) {
// Constructor code
}
};
MyClass obj1 = 10; // Error without 'explicit' (prevents implicit conversion)
MyClass obj2(10); // Correct usage
Note: Adding explicit
ensures that constructors are only used when explicitly invoked by the programmer.
4. constexpr
(C++11 and later)
- Purpose: Specifies that a function can be evaluated at compile time if given constant arguments.
- Use Case: Used for functions that compute values that will never change and should be known at compile-time, improving performance.
- Example:
constexpr int factorial(int n) {
return (n <= 1) ? 1 : (n * factorial(n - 1));
}
constexpr int result = factorial(5); // Compile-time evaluation
Note: For constexpr
functions, the arguments must be constant expressions, and the function itself must contain only constant expressions.
5. friend
(C++ only)
- Purpose: Grants a non-member function or class access to the private and protected members of another class.
- Use Case: Used when an external function or another class needs to access the internal details of a class, without exposing them publicly.
- Example:
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
friend void displayValue(const MyClass& obj);
};
void displayValue(const MyClass& obj) {
std::cout << "Value: " << obj.value << std::endl; // Can access private member
}
Note: friend
functions break the traditional encapsulation, so they should be used sparingly.
6. override
(C++11 and later)
- Purpose: Ensures that a function in a derived class is actually overriding a virtual function from the base class.
- Use Case: Prevents bugs caused by mistakenly not overriding a base class method due to mismatched signatures.
- Example
class Base {
public:
virtual void show() {}
};
class Derived : public Base {
public:
void show() override { // Ensures it's overriding
std::cout << "Derived class show" << std::endl;
}
};
Note: If the function does not actually override a base class function, the compiler will throw an error, making it a helpful debugging tool.
7. final
(C++11 and later)
- Purpose: Prevents further overriding of a virtual function or prevents a class from being inherited.
- Use Case: Used to restrict inheritance or method overriding to preserve the class or function’s intended behavior.
- Example:
class Base {
public:
virtual void display() final {
std::cout << "Base class final display function\n";
}
};
class Derived : public Base {
// Error: cannot override a final function
// void display() override;
};
Note: final
can also be applied to entire classes to prevent inheritance.
8. default
and delete
(C++11 and later)
- Purpose:
default
: Specifies that a default implementation of a function should be generated by the compiler.delete
: Specifies that a function cannot be used.
- Use Case: Used for managing special member functions such as constructors, destructors, or copy constructors.
- Example
class MyClass {
public:
MyClass() = default; // Compiler will generate default constructor
MyClass(const MyClass&) = delete; // Copy constructor is not allowed
};