This question讨论了箭头运算符->
如何自动重新应用于重载operator->()
的返回值,直到返回的值是原始指针,此时原始指针被解除引用,就像使用->
一样。但是,如果有一个指针到指针类型,他们希望取消引用基值,则情况不一样 - 它们必须使用(*ptr_to_ptr)->foo()
。在我看来,ptr_to_ptr->foo()
的用法将是明确的,甚至比返回值的->
自动重新应用直到返回原始指针更为明确。那么,这个决定背后的原因是什么?
最小的工作示例:
#include <iostream>
struct Dog {
void bark() { std::cout << "woof!" << std::endl; }
};
struct DogWalker {
Dog* dog;
Dog* operator->() {
return dog;
}
};
struct DogOwner {
DogWalker walker = { new Dog() };
DogWalker operator->() {
return walker;
}
};
void main()
{
DogOwner owner;
owner->bark(); // works, prints "woof"
Dog** ptr_to_ptr = new Dog*;
*ptr_to_ptr = new Dog;
(**ptr_to_ptr).bark(); // works
(*ptr_to_ptr)->bark(); // works
//ptr_to_ptr->bark(); // ERROR
//C2227: left of '->bark' must point to class/struct/union/generic type
}
答案 0 :(得分:2)
语言采用C语言的大部分语义。->
运算符应用于指针类型时仅在指针指向非数组复合类型时才有效。由于C没有类,因此C ++为重载的->
定义了自己的语义,这对于智能指针用例是有意义的。
您可以使用帮助程序类实现所需的行为。
template <typename T>
struct Unwrap {
T *p_;
Unwrap (T *p = 0) : p_(p) {}
T * operator -> () const { return p_; }
};
template <typename T>
struct Unwrap<T *> {
T **p_;
Unwrap (T **p = 0) : p_(p) {}
Unwrap<T> operator -> () const { return *p_; }
};
template <typename T>
Unwrap<T> make_unwrap (T *p) { return p; }
然后您可以像这样使用它:
struct foo {
void bar () { std::cout << "Hello\n"; }
};
int main () {
foo p;
auto pp = &p;
auto ppp = &pp;
auto pppp = make_unwrap(&ppp);
pppp->bar();
}