Operator Overloading in Delphi and C++

Let us consider the following toy problem: implement a user-defined integer type MyInt which is assignment compatible with built-in signed and unsigned integers and supports addition. We assume here that all integers are 32-bit. Assigning unsigned integers above 0x7fffffff to MyInt and assigning negative MyInt values to unsigned integers should raise exceptions.

To begin with we have a record (Delphi)

type
  MyInt = record
  private
    FValue: Integer;
  end;

or structure (C++)

struct MyInt{
private:
  int FValue;
};

By convention we use explicit conversion if a conversion can raise exception and implicit conversion otherwise. The Delphi solution is straightforward:

unit MyInts;

interface

uses SysUtils;

type
  MyInt = record
  private
    FValue: Integer;
  public
    class operator Implicit(AValue: MyInt): Integer;
    class operator Explicit(AValue: MyInt): Cardinal;
    class operator Implicit(AValue: Integer): MyInt;
    class operator Explicit(AValue: Cardinal): MyInt;
    class operator Add(A, B: MyInt): MyInt;
  end;

implementation

class operator MyInt.Explicit(AValue: MyInt): Cardinal;
begin
  if AValue.FValue < 0 then
    raise Exception.Create(IntToStr(AValue.FValue));
  Result:= AValue.FValue;
end;

class operator MyInt.Explicit(AValue: Cardinal): MyInt;
begin
  if AValue > $7FFFFFFF then
    raise Exception.Create(IntToStr(AValue));
  Result.FValue:= AValue;
end;

class operator MyInt.Implicit(AValue: MyInt): Integer;
begin
  Result:= AValue.FValue;
end;

class operator MyInt.Implicit(AValue: Integer): MyInt;
begin
  Result.FValue:= AValue;
end;

class operator MyInt.Add(A, B: MyInt): MyInt;
begin
  Result.FValue:= A.FValue + B.FValue;
end;

end.

With C++ we need more to take into account. First C++ supports copy initialization

  MyInt M = 1;

which is implemented by a constructor while a plain assignment requires either a conversion operator

  MyInt M;
  M = 1;

or an assignment operator

  MyInt M = 1;
  MyInt M1;
  M1 = M;

If we do not declare an assignment operator C++ implicitly provides the one which implements assignment by shallow coping; it is enough for our problem.

Second we have 2 possible ways to implement the addition operator – as a member function or as a plain function. The member function treats the operands of a binary operation asymmetrically – the first operand is passed as this pointer (different from Delphi which implements the operator member function as static) – and rarely used. More common is to implement a binary operation by a plain function which should be declared as friend in MyInt structure to enable access to the private field FValue.

Third the conversion operators in C++ are “one-way”. We can define the conversion operator FROM MyInt; conversion TO MyInt is implemented by a constructor.

There are more language details a C++ programmer should have in mind while implementing operator overloading; you will discover them if you start experimenting with the code. I leave them out of the article.

Putting it all together we are coming to the following code:

(MyInts.hpp)

#ifndef MYINTS_HPP_INCLUDED
#define MYINTS_HPP_INCLUDED

struct MyInt{
private:
    int FValue;
public:
    MyInt(int A = 0);
    MyInt(unsigned int A);
    MyInt(const MyInt& A);
//    MyInt operator=(MyInt A);

    operator int();
    operator unsigned int();
    friend MyInt operator+(const MyInt& A, const MyInt& B);
};

#endif // MYINTS_HPP_INCLUDED

(MyInts.cpp)

#include <iostream>
#include "MyInts.hpp"

using namespace std;

MyInt::MyInt(int A){
    cout << "hello from MyInt(int) ctor" << endl;
    FValue = A;
}

MyInt::MyInt(unsigned int A){
    cout << "hello from MyInt(unsigned int A) ctor" << endl;
    if (A > 0x7fffffff){
        cout << "throwing " << A << endl;
        throw(A);
    }
    FValue = A;
}

MyInt::MyInt(const MyInt& A){
    cout << "hello from MyInt(const MyInt&) ctor" << endl;
    FValue = A.FValue;
}

/*
MyInt MyInt::operator=(MyInt A){
    cout << "hello from assignment operator" << endl;
    FValue = A.FValue;
    return *this;
}
*/

MyInt::operator int(){
    cout << "hello from int conversion operator" << endl;
    return FValue;
}

MyInt::operator unsigned int(){
    cout << "hello from unsigned int conversion operator" << endl;
    if (FValue < 0){
        cout << "throwing " << FValue << endl;
        throw(FValue);
    }
    return FValue;
}

MyInt operator+(const MyInt& A, const MyInt& B){
    cout << "hello from addition operator" << endl;
    MyInt Result = A.FValue + B.FValue;
    return Result;
}
Advertisements

One thought on “Operator Overloading in Delphi and C++

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s