考虑以下示例:
class A { int x; };
现在什么是 A::x
?
- 它不可能是lvalue,因为它不参考存储位置。
- 它不能是一种类型,因为该类型将是
decltype(A::x)
。
实际上是lvalue。[expr.prim.id.qual]/2:
a 嵌套名称 - 指示符表示类[...]后跟 该类([class.mem](或其基础之一的成员的名称 类是A 合格的ID [...]。结果就是成员。方式 结果是成员的类型。结果是一个lvalue 该成员是静态成员函数或数据成员和prvalue 否则。
尽管其在类成员访问表达式以外的用法受[expr.prim.id]/2的严重限制,但它可以显然用于未升级的操作数中,其中其lvaluess可以表现出来:
struct A {
int x;
};
void f(int &);
using p = decltype(&(A::x)); // p is int*; the parens prevents forming a pointer-to-member
using q = decltype(f(A::x)); // q is void
A::x
只是一种不太模棱两可的参考成员 x
的方式,如果本地上下文 shadows 该成员是必不可少的:
示例1:
儿童课也有成员x
。
struct B : public A
{
int x;
void foo()
{
int local_x = x;
int parent_x = A::x;
}
}
如果您在类A
中制作x
protected
(当前是private
(。
示例2:
您甚至可以在x
的成员函数中使用它,该将CC_11作为参数:
class A {
int x;
void foo(int x)
{
int parameter_x = x;
int member_x = A::x;
}
};
除了Bathsheba的答案之外,当您在班级的范围内时,A::x
也可以用作指针到成员表达式的一部分,即返回的&A::x
int A::*
。
在这种情况下,独立的A::x
是无效的,因此返回的问题是模拟的。
来自C 标准(5.1主要表达式(
9嵌套名称的指示符,表示一个类,可选为 关键字模板(14.2(,然后是成员的名称 在该类别(9.2(或其基础类别之一(第10条(中, 合格的ID;3.4.3.1描述了班级成员的名称查找 出现在合格的ID中。结果就是成员。类型 结果是成员的类型。结果是一个LVALUE 成员是静态成员函数或数据成员和prvalue 否则。[注意:可以将类成员引用到使用 在其潜在范围的任何时刻,合格的ID(3.3.7(。 - 末端注释 ] ...
合格的名称允许指定一个原本隐藏的名称,例如,派生和基类的成员具有相同的名称。例如
#include <iostream>
struct A
{
int i;
};
struct B : A
{
B( int i ) : A { i }, i( 2 * A::i ) {}
int i;
std::ostream &out( std::ostream &os = std::cout ) const
{
return os << "A::i = " << A::i << ", B::i = " << B::i;
}
};
int main()
{
B( 10 ).out() << std::endl;
return 0;
}
程序输出是
A::i = 10, B::i = 20
也(5.1主要表达式(
13表示非静态数据成员或 类的非静态成员功能只能使用:
(13.1( - 作为对象的类成员访问(5.2.5(的一部分 表达式是指成员的class63或从中得出的类 班级或
(13.2( - 形成指向成员(5.3.1(或
的指针(13.3( - 如果该ID表达表示非静态数据成员,并且它 出现在未评估的操作数中。
A::x
与访问java中的静态变量的确切等同。
关于您的示例: -
1( X 对于不同的对象将是可变的
2( a :: x 将是类本身的变量。无论为每个对象声明了多少个对象,A::x
的值都相同,直到分配为止。
例如: -
#include<iostream>
using namespace std;
class A {
public:
static int x;
};
int A::x;
int main()
{
A a,b;
a.x=8;
b.x=6;
A::x=10;
return 0;
}