C++ Function Overloading and Operator Overloading

Function Rewriting

String Manipulation Functions

String Copy

char* customCopy(char* destination, const char* source) {
    char* result = destination;
    while (*destination++ = *source++);
    return result;
}

String Concatenation

char* customConcat(char* destination, const char* source) {
    char* result = destination;
    while (*destination) {
        destination++;
    }
    while (*destination++ = *source++);
    return result;
}

String Comparison

int customCompare(const char* str1, const char* str2) {
    const char* s1 = str1;
    const char* s2 = str2;
    while (*s1 && *s2 && *s1++ == *s2++);
    return *s1 - *s2;
}

String Length

size_t customLength(const char* str) {
    const char* temp = str;
    size_t length = 0;
    
    while (*temp) {
        temp++;
        length++;
    }
    
    return length;
}

Inheritance Fundamentals

Overview

Inheritance allows a new class to acquire properties and methods from an existing class. The existing class is known as the base class or parent class, while the new class is called the derived class or child class.

Inheritance Syntax

class DerivedClass : AccessSpecifier BaseClass {
    // Class members
};

Inheritance Types

Inheritance Type Base Class Member Access Derived Class Member Access
public public public
protected protected
private Not accessible
protected public protected
protected protected
private Not accessible
private public private
protected private
private Not accessible

Constructor and Destructor Behavior

Derived classes don't inherit constructors from base classes. Instead, they call base class constructors to initialize inherited members. The constructor execution order follows: base class constructors first, then derived class constructors.

Similarly, derived classes don't inherit destructors. However, unlike constructors, the compiler knows how to call destructors in inheritance relationships. The destructor execution order is the reverse of constructor execution order.

Function Name Conflicts

When a derived class has functions with the same name as base class functions, the derived class functions override the base class functions within the derived class context. To access base class functions, you need to specify them using the scope resolution operator with the class name.

Multiple Inheritance

C++ supports multiple inheritance, where a derived class can inherit from multiple base classes. If multiple base classes have functions with the same name, you can specify which one to use by qualifying with the base class name.

Virtual Inheritance

Virtual inheritance is a concept specific to multiple inheritance, particularly useful in diamond inheritance scenarios. It prevents duplication of inherited members from a common base class. The 'virtual' keyword is used to specify virtual inheritance.

Polymorphism

Concept

Polymorphism allows objects of different classes to be treated as objects of a common superclass. When a base class pointer points to a base class object, it calls base class methods. When it points to a derived class object, it calls derived class methods.

Requirements for Polymorphism

  1. Base class functions must be declared as virtual
  2. Derived class functions must override base class methods with the same name, return type, and parameter list
  3. There must be an inheritance relationship between the classes

Function Overloading, Overriding, and Hiding

  • Overloading: Multiple functions with the same name but different parameters in the same scope
  • Overriding: Derived class provides a specific implementation of a function that is already defined in its base class
  • Hiding: When a derived class defines a function with the same name as a base class function, but with different parameters

Pure Virtual Functions

A pure virtual function is declared in a base class but has no implementation. It's defined using the 'virtual' keyword and assigned to zero (e.g., virtual void function() = 0;). Classes containing pure virtual functions are abstract classes and cannot be instantiated. Abstract classes are used to define interfaces that derived classes must implement.

C++ String Class Operations

String Constructors

#include <iostream>
#include <string>

int main() {
    // Default constructor - creates an empty string
    str emptyStr;
    
    // Constructor with C-string
    str textStr("Hello World");
    
    // Copy constructor
    str copyStr(textStr);
    
    // Substring constructor
    substr subStr(copyStr, 5);
    
    // Output strings
    std::cout << "emptyStr: " << emptyStr << std::endl;
    std::cout << "textStr: " << textStr << std::endl;
    std::cout << "copyStr: " << copyStr << std::endl;
    std::cout << "subStr: " << subStr << std::endl;
    
    return 0;
}

String Length

#include <iostream>
#include <string>

int main() {
    str emptyStr;
    str textStr("Hello World");
    str copyStr(textStr);
    substr subStr(copyStr, 5);

    // Output strings
    std::cout << "emptyStr: " << emptyStr << std::endl;
    std::cout << "textStr: " << textStr << std::endl;
    std::cout << "copyStr: " << copyStr << std::endl;
    std::cout << "subStr: " << subStr << std::endl;

    // Get length
    std::cout << "emptyStr size: " << emptyStr.size() << std::endl;
    std::cout << "textStr size: " << textStr.size() << std::endl;
    std::cout << "copyStr size: " << copyStr.size() << std::endl;
    std::cout << "subStr size: " << subStr.size() << std::endl;
    std::cout << "emptyStr length: " << emptyStr.length() << std::endl;
    std::cout << "textStr length: " << textStr.length() << std::endl;
    std::cout << "copyStr length: " << copyStr.length() << std::endl;
    std::cout << "subStr length: " << subStr.length() << std::endl;

    return 0;
}

Accessing Characters

#include <iostream>
#include <string>

int main() {
    str textStr("Hello World");
    
    // Access using subscript operator
    std::cout << "textStr[2]: " << textStr[2] << std::endl;
    
    // Access using at() method
    std::cout << "textStr.at(2): " << textStr.at(2) << std::endl;
    
    return 0;
}

Appending Strings

#include <iostream>
#include <string>

int main() {
    str baseStr;
    
    // Append using += operator
    baseStr += "Hello ";
    baseStr += "World!";
    
    std::cout << "baseStr: " << baseStr << std::endl;
    
    // Alternative using append method
    str altStr;
    altStr.append("This is ");
    altStr.append("a test");
    
    std::cout << "altStr: " << altStr << std::endl;
    
    return 0;
}

Inserting Strings

#include <iostream>
#include <string>

int main() {
    str textStr("Hello World");
    
    // Insert substring at position 5
    textStr.insert(5, "Beautiful ");
    
    std::cout << "Modified textStr: " << textStr << std::endl;
    
    return 0;
}

Deleting Substrings

#include <iostream>
#include <string>

int main() {
    str textStr("Hello Beautiful World");
    
    // Erase 10 characters starting from position 6
    textStr.erase(6, 10);
    
    std::cout << "Modified textStr: " << textStr << std::endl;
    
    return 0;
}

Replacing Substrings

#include <iostream>
#include <string>

int main() {
    str textStr("Hello Beautiful World");
    
    // Replace 10 characters starting from position 6 with "Wonderful"
    textStr.replace(6, 10, "Wonderful");
    
    std::cout << "Modified textStr: " << textStr << std::endl;
    
    return 0;
}

Operator Overloading in C++

Introduction

Unlike C, C++ supports operator overloading, which allows you to redefine the behavior of operators for user-defined types. This enables you to use operators with objects in a way that's intuitive and consistent with their intended functionality.

Overloading Methods

Operator functions can be implemented in two ways:

  1. As member functions: Defined inside the class. The number of parameters is one less than the operands because the implicit 'this' pointer serves as the first operand.
  2. As friend functions: Defined inside or outside the class. The number of parameters matches the number of operands.

Syntax

// Member function
ReturnType operator OperatorSymbol(Parameters);

// Friend function
friend ReturnType operator OperatorSymbol(Parameters);

Implementation Forms

  • Can be implemented as class member functions
  • Can be implemented as global functions, declared as friends of the class

Unoverloadable Operators

  • sizeof (size operator)
  • :: (scope resolution operator)
  • ?: (conditional operator)
  • .* and ->* (pointer-to-member operators)
  • . (member access operator)
  • # (preprocessor operator)

Overloadable Operators

Binary Arithmetic Operators + (addition), - (subtraction), * (multiplication), / (division), % (modulo)
Relational Operators == (equality), != (inequality), < (less than), > (greater than), <= (less than or equal), >= (greater than or equal)
Logical Operators || (logical OR), && (logical AND), ! (logical NOT)
Unary Operators + (unary plus), - (unary minus), * (dereference), & (address of)
Increment/Decrement ++ (increment), -- (decrement)
Bitwise Operators | (bitwise OR), & (bitwise AND), ~ (bitwise NOT), ^ (bitwise XOR), << (left shift), >> (right shift)
Assignment Operators =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
Memory Management new, delete, new[], delete[]
Other Operators () (function call), -> (member access), , (comma), [] (subscript)

Must Be Members

The following operators must be overloaded as class members:

  • Assignment operator (=)
  • Subscript operator ([])
  • Function call operator ()
  • Pointer-to-member operator (->)

Best Practices

  • Prefer overloading binary operators as global functions (friends)
  • Prefer overloading unary operators as member functions

Relational Operator Overloading

When overloading relational operators, it's common to implement them in terms of each other to reduce redundancy. For example, you can implement != in terms of ==, and > in terms of <.

Input/Output Operator Overloading

The stream insertion (<<) and extraction (>>) operators are typically overloaded as global functions that take ostream& and istream& as parameters, respectively.

Subscript Operator Overloading

The subscript operator ([]) is commonly overloaded for container-like classes to provide array-like access to elements. It's often overloaded twice: one as a const version for read-only access and one as a non-const version for modification.

Increment/Decrement Operator Overloading

Increment (++) and decrement (--) operators can be overloaded in both prefix and postfix forms. The postfix version is distinguished by an unused int parameter.

new and delete Operator Overloading

You can overload new and delete operators to customize memory allocation and deallocation for your class. This is useful for implementing custom memory management strategies.

Custom String Class Implementation

Implementing a custom string class is a great exercise in operator overloading. It typically involves overloading assignment, concatenation, comparison, and subscript operators, among others.

Tags: C++ Function Overloading Operator Overloading Inheritance Polymorphism

Posted on Wed, 22 Jul 2026 16:14:40 +0000 by jasonscherer