286

从其他 C 派生语言(如 Java 或 C#)到 C++,C++ 具有三种引用类成员的方式一开始非常令人困惑:a::ba.ba->b. 我什么时候使用这些运算符中的哪一个?

_(注意:这是 [Stack Overflow 的 C++ 常见问题解答](https://stackoverflow.com/questions/tagged/c++-faq) 的一个条目。如果您想批评以这种形式提供常见问题解答的想法,然后[开始这一切的 meta 上的帖子](https://meta.stackexchange.com/questions/68647/setting-up-a-faq-for-the-c-tag)将是这样做的地方. 该问题的答案在 [C++ 聊天室](https://chat.stackoverflow.com/rooms/10/c-lounge) 中进行监控,FAQ 想法最初就是从那里开始的,所以你的答案很可能让提出这个想法的人阅读。)_
4

4 回答 4

294

C++ 用于访问类或类对象成员的三个不同的运算符,即双冒号::、点.和箭头->,用于三种不同的场景,这些场景总是定义明确的。知道这一点后,您可以立即了解很多,a并且b只需分别查看您查看的任何代码中的a::ba.b或。a->b

  1. a::b仅当b是类(或命名空间)的成员时才使用a。也就是说,在这种情况下,a将始终是类(或命名空间)的名称。

  2. a.b仅当b是对象的成员(或对对象的引用)时才使用a。因此,对于a.b,a将始终是类的实际对象(或对对象的引用)。

  3. a->b最初是 的简写符号(*a).b。但是,->是唯一可以重载的成员访问运算符,因此如果a是重载类的对象operator->(常见的此类类型是智能指针和迭代器),那么含义就是类设计器实现的任何内容。总结: With a->b, ifa是一个指针,b将是指针a所指对象的成员。但是,如果是重载此运算符的类的对象,则调用a重载的运算符函数。operator->()


小字:

  • 在 C++ 中,声明为classstructunion的类型被视为“类类型”。所以上面提到的都是他们三个。
  • 引用在语义上是对象的别名,所以我也应该在#3 中添加“或对指针的引用”。但是,我认为这会更令人困惑而不是有用,因为T*&很少使用对指针 ( ) 的引用。
  • 点和箭头运算符可用于引用对象中的静态类成员,即使它们不是对象的成员。(感谢奥利指出这一点!)
于 2011-02-13T14:11:48.407 回答
43

Suggesting an alternative for sbi's point 3

a->b is only used if a is a pointer. It is a shorthand for (*a).b, the b member of the object that a points to. C++ has two kinds of pointers, "regular" and smart pointers. For regular pointers such as A* a, the compiler implements ->. For smart pointers such as std::shared_ptr<A> a, -> is a member function of class shared_ptr.

Rationale: the target audience of this FAQ isn't writing smart pointers. They don't need to know -> is really called operator->(), or that it is the only member access method that can be overloaded.

于 2011-02-14T10:32:27.480 回答
10

点运算符用于直接成员选择场景。

print(a.b)

在这里,我们正在访问b,它是对象的直接成员a。因此,主要a是一个对象,并且ba.


箭头运算符用于间接成员选择场景。

print(a->b)

在这里,我们正在访问bwhich 是对象的成员,它由 指向a。它是简写,(*a).b所以在这里,a主要是指向对象的指针,并且b是该对象的成员。


双冒号(Scope)运算符用于命名空间相关的直接成员选择场景。

print(a::b)

在这里,我们访问b的是 class/namespace 的成员a。所以,主要a是 class/namespace 并且b是 的成员(函数/变量等)a

于 2020-01-24T06:06:44.287 回答
3
#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->
::.->

于 2019-08-16T14:10:32.153 回答