Why can I use double colons in functions and classes not defined but I can't use in variables ??
age
is an instance field, it exists in multiple places in memory - one for each Person
that exists.
I'll now expand in detail about what the ::
operator does, how to use it, and how static
class members compare to instance members:
The ::
operator:
The ::
(the scope-resolution operator) has multiple uses in C++:
If you're familiar with Java, C# or JavaScript then it can be likened to the dot dereference or "navigation operator" .
(e.g. namespace.Class.Method().Result
) - except C++ uses a different operators for different kinds of navigation and dereferencing:
.
is the member-access operator, similar to C - it's only applicable for "object values" and references (foo&
), not pointers (foo*
).
->
is another member-access operator for pointer types, note that this operator can be overridden but .
cannot (overridin ->
is risky but it improves the ergonomics of smart-pointer libraries when done correctly).
::
is the scope-resolution operator - it has a few different uses:
- Namespace navigation - whereas Java and C# use
.
to navigate packages and namespaces, C++ uses ::
, for example: using std::time
.
- When unqualified, it's also used to reference the global namespace, e.g.
::std
which is handy if you're writing code which is already in a namespace.
- It's also used to access static members of types - typically an actual
static
member (a static method or field) but also items like enum class
(scoped enumeration) values (e.g. SomeEnumClass::value_name
)
- Finally, it's also used to select a specific base method when dealing with
virtual
method implementations: it's used when an overridden method needs to call a base implementation in a superclass - C++ does not have the singular base
or super
keywords that C# and Java have (respectively) because C++ allows multiple inheritance, so you must specify the specific parent class name: How to call a parent class function from derived class function?
Anyway, in your case, it looks like you're confused about what instance and static members actually mean, so here is an illustration:
class Person {
public:
int height; // each Person has their own height, so this is an instance member
static int averageHeight; // but an individual Person doesn't have an "average height" - but a single average-height value can be used for all Persons, so this is a shared ("static") value.
int getAverageHeight() { // this is an instance method, btw
return Person::averageHeight; // use `Person::` to unambiguously reference a static member of `Person`
}
Person()
: height(0) {
// instance members should be initialized in the constructor!
}
}
// This will create an array of 10 people (10 different object instances).
// Each Person object (an instance) will have its own `height` in memory
Person* multiplePeople = new Person[10];
// btw, you probably should use `std::array` with an initializer instead:
// array<Person,10> multiplePeople{}; // <-- like this
// This sets a value to the `staticField` member, which exists only once in memory, that is, all Person instances share the same value for this member...
Person::averageHeight = 175; // 175cm
// ...for example:
assert( 175 == multiplePeople[3]->getAverageHeight() );
assert( 175 == multiplePeople[6]->getAverageHeight() );
// However instance members can have different values for each instance:
multiplePeople[3]->height = 170;
multiplePeople[6]->height = 180;
// Btw `height` is initialized to 0 in each Person's constructor.
assert( 170 != multiplePeople[0]->height );
assert( 180 != multiplePeople[7]->height );