访问类成员

要访问类对象的成员变量和成员函数,请使用 . 运算符:

struct SomeStruct {
  int a;
  int b;
  void foo() {}
};

SomeStruct var;
// Accessing member variable a in var.
std::cout << var.a << std::endl;
// Assigning member variable b in var.
var.b = 1;
// Calling a member function.
var.foo();

通过指针访问类的成员时,通常使用 -> 运算符。或者,可以取消引用实例并使用 . 运算符,尽管这种情况不太常见:

struct SomeStruct {
  int a;
  int b;
  void foo() {}
};

SomeStruct var;
SomeStruct *p = &var;
// Accessing member variable a in var via pointer.
std::cout << p->a << std::endl;
std::cout << (*p).a << std::endl;
// Assigning member variable b in var via pointer.
p->b = 1;
(*p).b = 1;
// Calling a member function via a pointer.
p->foo();
(*p).foo();

访问静态类成员时,使用::运算符,但是使用类的名称而不是它的实例。或者,可以使用 .-> 运算符分别从实例或指向实例的指针访问静态成员,其语法与访问非静态成员的语法相同。

struct SomeStruct {
  int a;
  int b;
  void foo() {}

  static int c;
  static void bar() {}
};
int SomeStruct::c;

SomeStruct var;
SomeStruct* p = &var;
// Assigning static member variable c in struct SomeStruct.
SomeStruct::c = 5;
// Accessing static member variable c in struct SomeStruct, through var and p.
var.a = var.c;
var.b = p->c;
// Calling a static member function.
SomeStruct::bar();
var.bar();
p->bar();

背景

-> 运算符是必需的,因为成员访问运算符 . 优先于解除引用运算符*

人们会期望*p.a 会取消引用 p(导致对 p 指向的对象的引用),然后访问其成员 a。但事实上,它试图访问 p 的成员 a,然后取消引用它。即*p.a 相当于*(p.a)。在上面的示例中,由于两个事实,这将导致编译器错误:首先,p 是一个指针,并且没有成员 a。其次,a 是一个整数,因此不能被解除引用。

对这个问题不常见的解决方案是明确控制优先级:(*p).a

相反,-> 运算符几乎总是被使用。它是第一个取消引用指针然后访问它的简写。即 (*p).ap->a 完全相同。

::运算符是作用域运算符,其使用方式与访问命名空间成员的方式相同。这是因为静态类成员被认为是在该类的范围内,但不被视为该类的实例的成员。由于历史原因,静态成员也允许使用普通的 .->,尽管他们不是实例成员; 这用于在模板中编写通用代码,因为调用者不需要关心给定的成员函数是静态的还是非静态的。