例如下面的代码:
class StrPtr{
public:
StrPtr() : _ptr(nullptr){}
//拷贝构造函数等省略...
std::string* operator->()
{
return _ptr;
}
private:
std::string *_ptr;
};
std::string* operator->()
/*
这句代码的格式不是类似于前导运算符吗?类似于std::string operator*(){//...}不正是*ptr?但是重载的->运算符却是ptr->这样使用的,请问是为什么?
而且std::string* operator->()返回的是指针,为什么可以直接在后面访问类成员,[比如说ptr->size()]?
我的疑问是这是如何实现的,这和我对运算符重载的直接理解有所差异。
*/
) is right associative, while member access operator (
When you overload a left-associative operator (such as*
and.
) is left associative. This is an example of different associativity of different symbols. In C++, when the symbols are the same, there will also be examples of different usages resulting in different associativity. For example:->
, etc.), the operator is often a binary operator. For
But what if this operator is a unary operator? This will be discussed on a case-by-case basis:+ - * / ()
,lhs op rhs
orlhs.operator op(rhs)
will be called. We Just overload the operator according to this function signature.operator op(lhs, rhs)
or
++
), for--
(left combination) andlhs op
(right combination), we have to find a way to distinguish different usages, So there will be function parameters for placeholders (op rhs
):int
call
lhs op
lhs.operator op(int)
call
op rhs
rhs.operator op()
), for
->
, there is no need for placeholder function parameters, and it can be directly written as a right-associative function signature, that is,lhs op
call
lhs op
lhs.operator op()
, the operator
ptr->mem
is interpreted differently depending on the type ofptr
:->
is a built-in pointer type, it is equivalent to
ptr
(*ptr).mem
is a class, it is equivalent to
ptr
ptr.operator->()->mem
it will recurse into:
Operatorptr->mem
is unary, while operator
For example, use the class->
is binary. Operator.
ultimately accesses members through operator->
, and.
operator is not allowed to be overloaded and can only be implemented by the compiler..
defined by the subject:
StrPtr
The last digression, C++ variable names should not start with an underscore. Starting with an underscore is reserved for the compiler. You can use
m_somemember
orsomemember_
as a private member name.The standard stipulates that the way is written has nothing to do with the type of return value being a pointer.
And the magic is that if what is returned is not a pointer but a class object that overloads the arrow operator, then the arrow operator of the class object will be called until an arrow operator returns a raw Pointer, then retrieve the content of the pointer and perform member access. This process can be infinitely nested and recursed layer by layer. If the compiler searches layer by layer and does not find an arrow operator that returns a raw pointer, it will report an error. For example, if it returns a class object that does not have an overloaded arrow operator, or a value such as int.
If you follow the general operator overloading logic, then the arrow operator should return a reference, and there seems to be no problem logically. But if the above situation occurs, I'm afraid there will be something like
-> -> ... ->
. I think this is probably one of the reasons.
I hope to communicate with people who have different understandings.
The standard stipulates that ->either calls -> that returns an object, returns a pointer, or reports an error.