从其他C来源的语言(如Java或C#)到C ++到来,这是起初很困惑的是C ++有三种方式来引用类的成员:a::b
,a.b
,和a->b
。什么时候使用这些运算符中的哪一个?
(注意:这本来是Stack Overflow的C ++ FAQ的一个条目。如果您想批评以这种形式提供FAQ的想法,那么在所有这些都开始的meta上的张贴将是这样做的地方。该问题在C ++聊天室中进行监控,该问题最初是从FAQ想法开始的,所以提出这个想法的人很可能会读懂您的答案。)
从其他C来源的语言(如Java或C#)到C ++到来,这是起初很困惑的是C ++有三种方式来引用类的成员:a::b
,a.b
,和a->b
。什么时候使用这些运算符中的哪一个?
(注意:这本来是Stack Overflow的C ++ FAQ的一个条目。如果您想批评以这种形式提供FAQ的想法,那么在所有这些都开始的meta上的张贴将是这样做的地方。该问题在C ++聊天室中进行监控,该问题最初是从FAQ想法开始的,所以提出这个想法的人很可能会读懂您的答案。)
Answers:
C ++用于访问类或类对象的成员的三个不同的运算符,即double Colon ::
,dot .
和arrow ->
,用于始终定义良好的三个不同方案。认识到这一点,您可以立即知道了很多有关a
,并b
只要看一眼a::b
,a.b
或a->b
分别,你看任何代码。
a::b
仅当b
是类(或名称空间)的成员时使用a
。也就是说,在这种情况下,a
它将始终是类(或名称空间)的名称。
a.b
仅当b
是对象的成员(或对对象的引用)时使用a
。因此,对于a.b
,a
它将始终是类的实际对象(或对对象的引用)。
a->b
最初是的简写形式(*a).b
。但是,->
是唯一可以重载的成员访问运算符,因此,如果a
是重载的类的对象operator->
(通常此类是智能指针和迭代器),则其含义是类设计器所实现的。得出以下结论:使用a->b
,如果a
是指针,b
则将是指针所a
引用的对象的成员。但是,如果a
是重载此运算符的类的对象,则将operator->()
调用重载的运算符函数。
小字:
class
,struct
或的类型union
被视为“类类型”。因此,以上提到了这三个方面。 T*&
很少使用对指针()的引用。operator*()
也可以重载,并且没有什么可以迫使该重载与operator->()
!保持一致。(我没有投票反对BTW,只是经过一连串重复重复才到达这里)
->
但是通过重载operator*
和使用.
。只有operator->
重载才能做到这一点。
为sbi的观点3提出替代方案
a->b
仅当a
是指针时使用。它是的缩写,指向的对象(*a).b
的b
成员a
。C ++有两种指针,“常规”指针和智能指针。对于常规指针,例如A* a
,编译器实现->
。对于诸如此类的智能指针std::shared_ptr<A> a
,->
是class的成员函数shared_ptr
。
基本原理:本常见问题解答的目标受众不是在编写智能指针。他们不需要知道->
真的叫做operator->()
,或者它是唯一可以重载的成员访问方法。
+1
只是为了提供替代答案。
->
任何C ++程序员都应该很快会见到的标准迭代器,它也有很多重载,因此说仅将其用于指针可能会造成混淆。
#include <iostream>
#include <string>
using namespace std;
class Human {
private:
int age;
public:
string name;
Human(int humanAge, string humanName)
: age(humanAge), name(std::move(humanName)) {}
void DoSomething() {
cout << age << endl;
}
static void DisplayAge(const Human& person) {
cout << person.age << endl;
}
// ...
};
int main() {
// Usage of Dot(.)
Human firstMan(13, "Jim"); // firstMan is an instance of class Human
cout << firstMan.name << endl; // accessing member attributes
firstMan.DoSomething(); // accessing member functions
// Usage of Pointer Operator (->)
Human* secondMan = new Human(24, "Tom");
cout << secondMan->name << endl; // accessing member attributes
secondMan->DoSomething(); // accessing member functions
cout << (*secondMan).name << endl; // accessing member attributes
(*secondMan).DoSomething(); // accessing member functions
// Usage of Double Colon (::)
Human::DisplayAge(firstMan);
firstMan.DisplayAge(firstMan); // ok but not recommended
secondMan->DisplayAge(firstMan); // ok but not recommended
delete(secondMan);
return 0;
}
从上面的编码示例中,我们看到:
*使用点运算符(.
)从实例(或对象)
访问成员(属性和函数)*从指针到对象(或由创建new
)访问成员(属性和函数)使用指针运算符(->
)
*使用双冒号(::
)从类本身访问静态成员函数,而无需将对象作为句柄。[ 注意:您也可以使用.
或->
不建议从实例中调用静态成员函数]
->
只能由在堆上分配的指针使用new
?下面,第二项,我想我真的很清楚->
是针对指针的。而且,在您减票之前,最好className::non_static_member_function()
自己尝试使用c ++ 14。引用不是指针,因此可以使用.
,我将在回答中更加清楚。
点运算符用于直接成员选择方案。
print(a.b)
在这里,我们正在访问b
,它是object的直接成员a
。因此,首先a
是的对象,并且b
是的成员(函数/变量等)a
。
箭头运算符用于间接成员选择方案。
print(a->b)
在这里,我们正在访问b
的对象的成员a
。它的缩写,(*a).b
因此在这里a
主要是指向对象的指针,并且b
是该对象的成员。
Double Colon(Scope)运算符用于与名称空间相关的直接成员选择方案。
print(a::b)
在这里,我们访问的b
是class / namespace的成员a
。因此,主要a
是class / namespace的并且b
是a
。
.
并且->
还可以通过对象来访问类静态,即使他们不是严格的“对象的成员”。