何时使用点、箭头或双冒号来引用 C++ 中的类的成员?

When do I use a dot, arrow, or double colon to refer to members of a class in C++?

提问人:sbi 提问时间:2/13/2011 最后编辑:Communitysbi 更新时间:1/24/2020 访问量:102912

问:

从其他 C 派生语言(如 Java 或 C#)到 C++,起初非常令人困惑的是,C++ 有三种方式来引用类的成员:、 和 。何时使用这些运算符中的哪一个?a::ba.ba->b

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

评论


答:

316赞 sbi 2/13/2011 #1

C++ 用于访问类或类对象成员的三个不同运算符,即双冒号、点和箭头,用于始终定义良好的三种不同方案。知道这一点可以让你立即知道很多,并且只需在你查看的任何代码中分别查看 、 或 。::.->aba::ba.ba->b

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

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

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


小字:

  • 在 C++ 中,声明为结构联合的类型被视为“类类型”。所以以上指的是他们三个。
  • 从语义上讲,引用是对象的别名,所以我也应该在#3中添加“或引用指针”。但是,我认为这比帮助更令人困惑,因为很少使用对指针 (T*&) 的引用。
  • 点和箭头运算符可用于引用对象中的静态类成员,即使它们不是对象的成员。(感谢 Oli 指出这一点!

评论

13赞 Oliver Charlesworth 2/13/2011
应该澄清的是,它也可以用于通过对象访问类静态,即使它们不是严格意义上的“对象成员”。.->
0赞 sbi 2/13/2011
@Oli:确实如此。我已将它添加到小字体中,因为我认为它并不常见且重要,无法列在正文中。
4赞 juanchopanza 7/4/2013
为了完整起见,可能值得指出的是,它也可以被重载,并且没有任何东西强制该重载与 !(顺便说一句,我没有投反对票,只是通过一长串重复项来到这里)operator*()operator->()
0赞 the swine 1/16/2014
您@OliCharlesworth知道C++标准中在哪里指定?
1赞 Ben Voigt 9/3/2014
@juanchopanza:但是,您无法通过重载和使用 来获得链接行为。只有重载才能做到这一点。->operator*.operator->
44赞 MSalters 2/14/2011 #2

建议 SBI 第 3 点的替代方案

a->b仅当指针时才使用。它是 的简写,指向的对象的成员。C++ 有两种指针,“常规”指针和智能指针。对于常规指针,例如 ,编译器实现 .对于智能指针,例如 ,是类的成员函数。a(*a).bbaA* a->std::shared_ptr<A> a->shared_ptr

基本原理:本 FAQ 的目标受众不是在编写智能指针。他们不需要知道 -> 实际上被称为 operator->(),或者它是唯一可以重载的成员访问方法。

评论

8赞 sbi 2/14/2011
不管我是否同意,我都只是为了提供一个替代答案。+1
2赞 Kiscsirke 3/31/2013
好吧,公平地说,对于任何 C++ 程序员都应该很快遇到的标准迭代器来说,它也是超载的,所以说它只用于指针可能会令人困惑。->
0赞 Caleth 9/21/2017
@Kiscsirke“普通C++程序员”不需要编写智能指针或迭代器类型,只需使用它们即可。“像指针一样取消引用”适用于两者。
5赞 Hu Xixi 8/16/2019 #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->::.->

评论

0赞 Hu Xixi 9/5/2019
@sbi脾气暴躁哈,我知道这是某种重复。我只想举一个明确的例子来说明如何使用它们。我说过的地方只能由在堆上分配的指针使用?下面,第二项,我想我真的说得很清楚,这是指针。在你投反对票之前,你最好自己尝试一下 c++14。Reference 不是指针,所以可以使用 ,我会在我的回答中说得更清楚。->new->className::non_static_member_function().
18赞 muditrustagii 1/24/2020 #4

点运算符用于直接成员选择方案。

print(a.b)

在这里,我们正在访问 ,它是对象的直接成员。因此,首先,是一个对象,并且是 的成员(函数/变量等)。baaba


箭头运算符用于间接成员选择方案。

print(a->b)

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


双冒号(作用域)运算符用于与命名空间相关的直接成员选择方案。

print(a::b)

在这里,我们正在访问哪个是 class/namespace 的成员。因此,首先,是一个类/命名空间,并且是 的成员(函数/变量等)。baaba