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

sbi*_*sbi 237 c++ c++-faq

即将从其他C来源的语言(如Java或C#)到C++,它是第一个非常混乱的是C++有三种方式来引用类的成员:a::b,a.b,和a->b.我什么时候使用这些运营商中的哪一个?

(注意:这是Stack Overflow的C++常见问题解答的一个条目.如果你想批评在这种形式下提供常见问题解答的想法,那么发布所有这些的元数据的发布将是这样做的地方.这个问题在C++聊天室中受到监控,其中FAQ的想法一开始就出现了,所以你的答案很可能被那些提出想法的人阅读.)

sbi*_*sbi 237

C++用于访问类或类对象成员的三个不同运算符,即双冒号::,点.和箭头->,用于三个始终定义良好的不同场景.认识到这一点,您可以立即知道了很多有关a,并b只要看一眼a::b,a.ba->b分别,你看任何代码.

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

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

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


小字:

  • 在C++中,声明为class,struct或被union视为"类类型"的类型.所以上面提到了所有这三个.
  • 从语义上来说,引用是对象的别名,所以我应该在#3中添加"或引用指针".但是,我认为这会让人感到困惑,因为T*&很少使用对pointers()的引用.
  • 点和箭头运算符可用于引用对象中的静态类成员,即使它们不是对象的成员.(感谢Oli指出这一点!)

  • 应该澄清的是,`.`和` - >`也可以用来通过对象访问类静态,即使它们不是严格的"对象成员". (10认同)
  • 为了完整起见,可能值得指出`operator*()`也可以重载,并且没有什么能强制重载与`operator - >()`一致!(我没有关注BTW,只是通过一长串重复来到这里) (3认同)

MSa*_*ers 36

建议替代sbi的第3点

a->ba在指针使用时才使用.它是一个速记(*a).b,则b该对象的构件a指向.C++有两种指针,"常规"和智能指针.对于常规指针,例如A* a,编译器实现->.对于智能指针,如std::shared_ptr<A> a,->是类的成员函数shared_ptr.

理由:此常见问题解答的目标受众不是编写智能指针.他们不需要知道->是真的被调用operator->(),还是它是唯一可以重载的成员访问方法.

  • 不管我是否同意,我给它一个"+ 1"只是为了提供一个替代答案. (4认同)
  • 好吧,公平的` - >`对于标准迭代器来说也是重载的,任何C++程序员都应该很快就会遇到它,所以说它只用于指针可能会令人困惑. (2认同)

mud*_*gii 6

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

print(a.b)
Run Code Online (Sandbox Code Playgroud)

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


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

print(a->b)
Run Code Online (Sandbox Code Playgroud)

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


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

print(a::b)
Run Code Online (Sandbox Code Playgroud)

在这里,我们正在访问bwhich 是类/命名空间的成员a。因此,主要a是类/命名空间,并且b是 的成员(函数/变量等)a


Hu *_*ixi 5

#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;
}
Run Code Online (Sandbox Code Playgroud)

从上面的编码示例中,我们看到:
* 使用点运算符 ( ) 从实例(或对象)访问成员(属性和函数.
* 从指向对象(或由 )创建的指针访问成员(属性和函数new)使用指针运算符 ( ->)
* 使用双冒号 ( ) 从类本身访问静态成员函数,而无需使用对象作为句柄::。[注意:.您还可以使用或 来从实例调用静态成员函数,->但不推荐]