从其他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。
.并且->还可以通过对象来访问类静态,即使他们不是严格的“对象的成员”。