Concepts / Data Members and Object State in C++

Data Members and Object State in C++

A class declaration defines a new class type and lists its members: member functions and data members.

  • Programming

Bundling Data With Operations

Programs often need to represent a thing that has both data and operations on that data. C++ handles this with a class declaration, the statement that defines a new class type, gives that type a name, and lists what belongs to it. Once a class type is defined, you can work with values of that type in the same way you work with built-in types such as int and double. The running example in this article is a class named Vector, a small container that holds a sequence of double values. Start by reading its declaration, then work through what each part tells you.

What do you think happens?

Given the Vector declaration, which members can code outside the class use directly: the data members elem and sz, or the public member functions?

  • elem and sz

  • Vector, operator[], and size

  • All five members

Reveal answer
Answer:

Vector, operator[], and size. These are the public members, so code outside the class can use them. The private data members elem and sz are not reachable from outside the class.

The public and private access specifiers control who can use the members that follow them. Public members are accessible from anywhere, and private members are accessible only within the class. The public member functions form the interface through which outside code reaches the data the class holds.

Following an Object Through Member Calls

An object is a value of a class type, and it holds its own state, meaning the particular values stored in its data members at a given moment. A member function can read and change those stored values. To see how this works, consider a small generated example, Counter, which is not from the source. It has one private data member, count, that stores a number, and two public member functions: increment, which changes the stored number, and value, which reports it.

cpp

Trace what happens to one Counter object, c. Before the call c.increment(), its data member count holds 0. The call to increment is a member function doing its job: it accesses and manipulates the data member count, so afterwards count holds 1. The object's data member has changed, but the declaration itself has not. Only the stored state moved. Calling the function again would move the state again, while another Counter object would keep its own separate count.

count0count1after c.increment()
What changes in the count data member when increment is called on one Counter object?

Reading the Parts of a Class Declaration

The Vector declaration follows a clear pattern. The keyword class is followed by the name Vector, and the body is enclosed in braces. The body is divided into labeled sections by the words public and private, each followed by a colon. The declaration ends with a closing brace and a semicolon, and every member declaration inside the body ends with its own semicolon. The declaration includes the class name, access specifiers, member functions, and data members, and every member belongs to one of the two access sections.

classstarts a new class typeVectorclass namepublic:access section for theinterfaceVectorconstructor, publicoperator[]member function, publicsizemember function, publicprivate:access section for storedvalueselemdata member, pointer todoubleszdata member
How are the class name, access sections, member functions, and data members nested within one class declaration?

The access specifier applies to every member after it, until the next specifier appears. This is why the Vector declaration needs no separate label on each line: the public: label covers the constructor, operator[], and size, and the private: label covers elem and sz. The access specifier is a property of the section, not of an individual declaration.

  1. 1
    Find the access labels first, public or private, each followed by a colon.
  2. 2
    Assign every member declared after a label to that label's section, until the next label appears.
  3. 3
    Sort each member by whether it is followed by a parameter list. Declarations with a parameter list are member functions. Plain variable declarations are data members.

Public and Private Access Boundaries

The access specifiers decide what code outside the class can reach. Public members are accessible from anywhere. Private members are accessible only within the class. In the Vector declaration, the public member functions are the interface, and the private data members elem and sz hold the stored values. Outside code therefore calls the public functions and never touches elem or sz directly.

Code outside theclasspublic sectionVectorconstructorprivate sectionoperator[]member functionsizemember functionelemdata memberszdata membercontainscontainscontainscontainscontainscan usecan usecan useblockedblocked
Which members can code outside the class reach directly, and which are blocked by the class boundary?

Here is a second, generated class to practice on. Thermostat has two public member functions and one private data member.

cpp
Worked example

Predicting which Thermostat members outside code can use

Using the Thermostat declaration above, decide which members code outside the class can use directly.

  1. 1
    Find the access labels

    There is a public label followed by a private label. Members after public are in the public section, and members after private are in the private section.

  2. 2
    Sort the members

    set_target(double t) and read_target() are followed by parameter lists, so they are member functions. target_value is a plain variable declaration, so it is a data member.

  3. 3
    Assign each member to a section

    set_target and read_target sit under public. target_value sits under private.

  4. 4
    Apply the access rule

    Public members are accessible from anywhere, and private members are accessible only within the class. Outside code can use set_target and read_target, but it cannot use target_value directly.

Result

Outside code can call set_target and read_target. It cannot access target_value directly, so any change to the stored value has to go through a public member function.

Member Functions Versus Data Members

Member functions and data members are both declared inside the class body, but they play different roles. A member function is a function that is part of the class, and its job is to access and manipulate data members. A data member is a variable that is part of the class, and its job is to store data within a class object. The source notes that data members can be accessed and manipulated using member functions, which is the pattern visible in Vector: the data members elem and sz are private, while the member functions are public.

AspectMember functionData member
Role in the classAccesses and manipulates data membersStores data within a class object
How it is declaredFollowed by a parameter listA plain variable declaration
Members of VectorVector, operator[], sizeelem, sz
Typical access in Vectorpublicprivate
What it providesThe interface outside code usesThe stored values the class holds

Roles of member functions and data members in the Vector declaration

Class Types and Their Separate Objects

A class declaration is a blueprint. It defines the class type once, and each object created from that type gets its own data members. Two Vector objects therefore share the same declaration and the same member functions, but each one holds its own elem and sz values. Changing the stored state of one object does not change the stored state of the other.

Vector classdeclarationdefines the class typeobject aits own elem and sz valuesobject bits own elem and sz valuescreatescreates
How does one class declaration relate to the multiple object instances created from it, each with its own state?

The elem and sz Pair as a Stored Sequence

The source includes a comment on the elem data member: elem points to an array of sz doubles. The two data members work together. elem records where the stored doubles live, and sz records how many there are. Neither member alone describes the whole collection. Knowing where the values are without knowing how many there are does not describe a sequence, and knowing the count without the location does not give access to the values. Together, the two data members let a class describe a sequence of values.

elem[0]a doubleelem[1]a doubleelem[2]a double
How are the elements of the array that elem points to laid out and indexed inside the object?

The diagram shows one illustrative case in which sz is 3, so elem points to an array of three doubles, indexed from 0 to 2. The value of sz is what tells you how many of those positions belong to the sequence. The array itself is not a separate named member; it is the storage that elem points to, and the object keeps track of it through the pair of data members.

Mistakes Beginners Make With Access and Members

  • Common mistake

    Assuming an access label applies only to the next line

    What it looks like

    In Vector, a reader might think only the constructor is public because it comes first under public:

    Why it fails

    The access specifier applies to every member after it, until the next specifier appears.

    Do this instead

    Read the whole section. The public: label covers the constructor, operator[], and size.

  • Common mistake

    Assuming a data member is usable from outside because it is declared in the class

    What it looks like

    Writing code outside the class that reads target_value from a Thermostat object

    Why it fails

    Private members are accessible only within the class, so being declared in the class body does not make a member public.

    Do this instead

    Use the public member function, such as read_target, to reach the stored value.

  • Common mistake

    Calling a plain variable declaration a member function

    What it looks like

    Treating target_value as a function because it appears inside the class

    Why it fails

    Member functions are declarations followed by a parameter list. A plain variable declaration is a data member.

    Do this instead

    Check for a parameter list. target_value has none, so it is a data member.

  • Common mistake

    Thinking elem alone describes the whole sequence

    Why it fails

    elem records where the doubles live, but sz records how many there are. Neither member alone describes the whole collection.

    Do this instead

    Read the two data members together when you describe what the object stores.

Practicing a Declaration Read

EASY

Consider this generated declaration. Without running any code, list which members code outside the class can use directly, and which data members hold the object's state.

class Timer {
public:
    void start();
    int elapsed();
private:
    int ticks;
};
Hints
  • Start by finding the access labels. Which members come after public, and which come after private?
  • A member followed by a parameter list is a member function. start() and elapsed() both have parameter lists, even if the lists are empty.
  • Data members are the stored values. ticks is a plain variable declaration in the private section.

Key Takeaways

  • A class declaration defines a new class type, gives it a name, and lists its members, which are member functions and data members.
  • The public and private access specifiers apply to every member after them, and public members are reachable from outside the class while private members are not.
  • Member functions access and manipulate data members, while data members store the state of each object.
  • Each object created from a class type has its own data members, so calling a member function changes only the state of the object it is called on.
  • In the Vector declaration, the public member functions form the interface, and the private data members elem and sz together describe the stored sequence of doubles.

Related concepts

More concepts starting with D