Overloading binary operators in D

Operator overloading in object-oriented programming

Operator overloading is a type of compile-time polymorphism. In this process, the compiler determines which function to execute from a group of functions with the same name based on the types of parameters involved.

Polymorphism and operator overloading
Polymorphism and operator overloading

In D language, we can overload binary operators by defining special methods within our custom type.

The method name corresponds to the overloaded operator. By overloading binary operators, we can make the operators behave for our defined struct as per our requirements.

The opBinary and opCmp methods

The opBinary method is a generic function that takes a string op representing the operator and is used to overload binary operators like +, -, *, = etc. In the opBinary method, the condition if (op == "...") is used to specify which operator is being overloaded. While opCmp is used to overload comparison operators like <, <=, ==, !=, >=, >. This method generally returns 0 for equality, a negative value for less than, and a positive value for greater than.

Binary operators are broadly divided into four categories:

  • Arithmetic operators

  • Assignment operators

  • Bitwise operators

  • Relational operators

Following are the code examples for each type of binary operator.

Example 1: Overloading the arithmetic operator

import std.stdio;
struct Vector {
int x, y;
// Overloading the + operator
Vector opBinary(string op)(Vector other) if (op == "+") {
return Vector(x + other.x, y + other.y);
}
}
void main() {
Vector v1 = Vector(1, 2);
Vector v2 = Vector(3, 4);
Vector v3 = v1 + v2;
// Now v3.x will be 1 + 3 = 4, v3.y will be 2 + 4 = 6
writeln("(", v3.x, ", ", v3.y, ")");
}

Explanation:

  • Line 1: A package for input-output operations is imported.

  • Line 2: A struct Vector is defined as having two member variables.

  • Lines 5–7: The + operator is overloaded using the opBinary method. This function takes another Vector as an argument and returns a new Vector with the added components.

  • Lines 11–12: Two Vector objects are declared and initialized.

  • Line 13: Another Vector object is declared that is initialized using the overloaded + operator.

  • Line 15: The output is displayed.

Example 2: Overloading the assignment operator

import std.stdio;
struct Vector {
int x, y;
// Overloading the assignment operator
void opBinary(string op)(string newValue) if (op == "=") {
value = newValue;
}
}
void main() {
Vector v1 = Vector(1, 9);
Vector v2 = v1;
writeln("(", v2.x, ", ", v2.y, ")");
}

Explanation:

  • Line 1: A package for input-output operations is imported.

  • Line 2: A struct Vector is defined as having two member variables.

  • Lines 5–7: The = operator is overloaded using the opBinary method. This function takes another Vector as an argument and returns the result of comparison.

  • Line 11: A Vector object is declared and initialized.

  • Line 12: Another Vector object is declared and initialized with the overloaded assignment operator.

  • Line 13: The result of the assignment is displayed.

Example 3: Overloading bitwise operator

import std.stdio;
struct Bitwise {
int bits;
Bitwise opBinary(string op)(Bitwise other) if (op == "&") {
return Bitwise(bits & other.bits);
}
}
void main() {
Bitwise b1 = Bitwise(5); // 5 in integer = 0101 in binary
Bitwise b2 = Bitwise(3); // 3 in integer = 0011 in binary
Bitwise result = b1 & b2; // 0001 in binary = 1 in integer
writeln("Result: ", result.bits);
}

Explanation:

  • Line 1: A package for input-output operations is imported.

  • Line 2: A struct Bitwise is defined as having an integer member variable.

  • Lines 4–6: The & operator is overloaded using the opBinary method. This function takes another Bitwise object as an argument and returns the result of bitwise and.

  • Lines 10–11: Two Bitwise objects are declared and initialized.

  • Line 12: The overloaded relational operator & is called, and the result is stored in another Bitwise object.

  • Line 13: The result of the bitwise and is displayed.

Example 4: Overloading the relational operator

import std.stdio;
struct Vector {
int x, y;
// Overloading the relational operator ">"
int opCmp(Vector other) {
if (x == other.x && y == other.y) return 0;
return (x > other.x && y > other.y) ? 1 : -1;
}
}
void main() {
Vector v1 = Vector(1, 2);
Vector v2 = Vector(3, 4);
bool result = v1 > v2;
writeln("Result: ", result);
}

Explanation:

  • Line 1: A package for input-output operations is imported.

  • Line 2: A struct Vector is defined as having two member variables.

  • Lines 5–8: The > operator is overloaded using the opCmp method. This function takes another Vector as an argument and returns the result of comparison.

  • Lines 12–13: Two Vector objects are declared and initialized.

  • Line 14: The overloaded relational operator > is called, and the result is stored in a variable.

  • Line 15: The result of the comparison is displayed.

In summary, overloading binary operators in D enhances code expressiveness and flexibility, enabling developers to create more intuitive and readable programs. This feature, demonstrated in this answer in terms of syntax and importance, provides an amazing tool for achieving polymorphism and adhering to object-oriented programming principles in the D language.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved