Operator Overloading  «Prev  Next»

Overloading the Pointer Operator (operator->) in C++

Goal. Understand how to implement operator-> correctly for wrappers and iterators, with modern C++ practices (const-correctness, exception guarantees, and clear ownership).

1) What operator-> must return

The result of operator-> must either be:

That design allows seamless member access like obj->member().

2) Minimal wrapper example (modernized)

This example wraps a pointer to Triple and controls access, but uses modern headers, int main(), and const-correct overloads.

#include <iostream>

struct Triple {
  int i, j, k;
  void print() const {
    std::cout << "\ni = " << i
              << ", j = " << j
              << ", k = " << k;
  }
};

// Thin wrapper that optionally grants access to the underlying Triple
class TPtr {
  bool access_;
  Triple* ptr_; // educational: raw pointer with trivial lifetime rules
public:
  TPtr(bool access, Triple* p) : access_(access), ptr_(p) {}

  // const and non-const overloads; noexcept because it just returns a pointer
  Triple* operator->() noexcept {
    return access_ ? ptr_ : nullptr;
  }
  const Triple* operator->() const noexcept {
    return access_ ? ptr_ : nullptr;
  }
};

int main() {
  Triple a{1,2,3}, b{4,5,6};
  TPtr ta(false, &a), tb(true, &b);

  if (ta.operator->() != nullptr) ta->print();   // no access → nullptr, guard if needed
  if (tb.operator->() != nullptr) tb->print();   // access granted
}

3) Implementing operator-> for an iterator

Custom iterators usually provide both operator* and operator->. The latter should return a pointer to the element so member access is natural:

template <class T>
class SimpleIter {
  T* p_ = nullptr;
public:
  using value_type        = T;
  using reference         = T&;
  using pointer           = T*;
  using difference_type   = std::ptrdiff_t;
  using iterator_category = std::random_access_iterator_tag;

  explicit SimpleIter(T* p) : p_(p) {}

  reference operator*()  const noexcept { return *p_; }
  pointer   operator->() const noexcept { return  p_; }

  // ... ++, --, +, -, ==, <, etc. as needed
};

4) Best practices and pitfalls

5) Modernized version of the legacy sample

This keeps the spirit of the original example while fixing headers and main, and using nullptr on denied access.

#include <iostream>

struct Triple {
  int i, j, k;
  void print() const {
    std::cout << "\ni = " << i
              << ", j = " << j
              << ", k = " << k;
  }
};

class TPtr {
  bool access_;
  Triple* ptr_;
public:
  TPtr(bool access, Triple* p) : access_(access), ptr_(p) {}
  Triple* operator->() noexcept { return access_ ? ptr_ : nullptr; }
  const Triple* operator->() const noexcept { return access_ ? ptr_ : nullptr; }
};

int main() {
  Triple a{1,2,3}, b{4,5,6};
  TPtr ta(false, &a), tb(true, &b);
  if (tb.operator->() != nullptr) tb->print();
}

Overload Indirect Member Selection

Click the Exercise link below to overload the -> operator for the vector class so the operator implements an iterator.
Overload Indirect Member Selection

SEMrush Software