如何重载箭头取消引用 operator->() 不是针对实体对象而是针对指针

How to overload the arrow dereference operator->() not for solid objects but for pointers

我知道如何为实体(堆栈)对象(如智能指针)重载运算符->

#include <iostream>
struct A { void foo() {} };
struct B {
    A* pa;
    A* operator->() {
        return pa;
    }
};
int main() {
    B b;
    b->foo();  // b is SOLID object on stack: b.pa = ...
}

但我想要这个:

B * pb = new B();
pb->foo(); // to call my overload

数据库管理器单例设计需要这个:

class DatabaseManager
{
private:
    static DatabaseManager * sharedInstance_;
    sqdb::Db *db = nullptr;

public:
    static DatabaseManager * instance();
    sqdb::Db * operator->() {
        return db;
    }
}

我基本上想要这种行为

auto m = DatabaseManager::instance();
m->Query(...); // db->Query 

您不能在指针上替换 ->

您可以创建一个重载 -> 的智能指针1,但不能重载内置运算符。

auto m = DatabaseManager::instance();
m->Query(...); // db->Query 

这没问题,但是 m 的类型不是指针。这将是一些 structclass 与超载 operator->.

这样的 class 可以只是 unique_ptrshared_ptr 的薄包装,而 -> 可以 return &(ptr.get()->db)例如。

最愚蠢的方法是

class DatabaseManager {
  struct DatabaseManagerPtr {
    DatabaseManager* ptr;
    sqdb::Db * operator->() {
      return ptr?ptr->db:nullptr;
    }
  };
  friend struct DatabaseManagerPtr;
private:
  static DatabaseManager * sharedInstance_;
  sqdb::Db *db = nullptr;

public:
  static DatabaseManagerPtr instance() {
    return {sharedInstance_};
  }
};

这使您的 "I want this to work" 代码完全按原样工作,但还有许多更聪明的方法可以做到这一点(可能涉及对您的 "I want this to work" 代码进行轻微调整)


1 在 C++ 中,智能指针是任何类似于指针的类型,但在某种程度上 "smarter" 比原始指针合理.也许只是穿了一套比较花哨的西装; C++ 在调用事物 "smart" 指针方面不是很精英。

规则是:

An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism

When operator-> returns, the operator -> is applied to the value returned, with the original second operand.

太容易理解了:只有 .operator->() 的链式调用可以减少为单个 -> 然后下面的指针解引用也将是 "reduced".

所以在这种情况下只需将instance函数更改为returnDatabaseManager&