Member Functions
 

Member functions and Interfaces

Input stream, member functions (methods), return values, interfaces, functions returning void.

So far we have been constructing and destroying objects. What else can we do to an object? We can't access its private data members, because the compiler wouldn't let us (not to mention that I haven't even talked about the syntax one would use to do it). It turns out that only the object itself (as specified in its class definition) can make a decision to expose some of its behavior and/or contents. Behavior is exposed via member functions, also called methods. If a member function is public, anybody can call it (we'll see the syntax in a moment).

Our first member function is called GetValue. It returns an int. From the implementation of this function we can see that the returned value is that of the private data member _num. Now we know what it means to have access to an object; it means to be able to invoke its member functions. Here, the object num of the type InputNum is defined in the scope of main and that's where we can access it. And access we do, calling num.GetValue(). To put it in different words, we invoke the method GetValue() on the object num. Or, we are getting the value of object num. In still other words (Smalltalk-speak) we send the message GetValue to the object num. What we are getting back is an int, which we print immediately using our old friend std::cout.

Download the Input series of sources
Download!
source
#include <iostream>

class  InputNum
{
public:
    InputNum ()
    {
        std::cout << "Enter number ";
        std::cin >> _num;
    }

    int GetValue () const {  return _num; }
private:
    int _num;
};

int main()
{
    InputNum num;
    std::cout << "The value is " << num.GetValue() << "\n";
    return 0;
}

A few words of syntax clarification are in order. The type of the return value is always specified in front of the member function definition (or declaration, as will be explained later). A method that is supposed to return something must have a return statement at the end (later we'll see that a return from the middle is possible, too). If a function is not supposed to return anything, its return type is void. In all our previous examples main wasn't returning anything, so it was declared void.

Not this time though. It turns out that main can return an integer. In fact it always returns an integer, even if it is defined as returning void (in that case it returns a more or less random number). By convention, main is supposed to return 0 if the program was successful. Otherwise it is supposed to return an error level. You can check for the error level after you've run your program from a batch file using the statement similar to this:
if not errorlevel 1 goto end

The keyword const following the declaration of a method, as in
int GetValue () const
means that this method does not change the state of the object. The compiler will not allow such a method to perform assignment, increment, or decrement of any data member, nor will it permit this method to call any non-constant methods of that class.

Moreover, only methods declared const may be called on a const object. So far we've seen a const object _matter inside World. If Matter had a const method, like GetValue, it would have been okay to call it in the context of the object _matter (that is: _matter.GetValue() would compile all right). We'll see examples of that later.

By the way, _num cannot be declared const any more, since it is not initialized in the preamble. The code in the body of the constructor is changing the (undefined) value of _num. Try compiling this program with a const _num and you'll see what happens.

When the object num of class InputNum is constructed in main, it prompts the user to input a number. It then waits for a number and stores it in its private data member _num. This is done through the services of the input object std::cin. Std::cin gets input from the keyboard and stores it in a variable. Depending on the type of the variable, std::cin expects different things from the keyboard. For instance, if you call it with an int, it expects an integer; if you call it with a double, it expects a floating point number, etc.

The set of public methods is called the interface and it defines the way clients may interact with the object. InputNum, for instance, provides read-only access to its contents. Because of that, we are guaranteed that the value of InputNum will never change once it is created. Successive calls to GetValue() will always return the same value.

If it makes sense, it is also possible for an object to grant write access to its contents--for example, in our case, by defining the method
void SetValue (int i) { _num = i; }

Then, after the call
num.SetValue (10);
subsequent calls to GetValue would return 10, no matter what number was input in the constructor of num. By the way, the equal sign in C++ signifies assignment (same as := in Pascal). The statement
_num = i;
sets the value of _num to that of i. Of course the method SetValue cannot be defined const, because it changes the state of the object (try it!). And if Matter had such a non-constant method, that method couldn't have been called in the context of the constant object _matter inside the World. The compiler would have strongly objected.

To summarize, the set of public member functions defines the interface to the object of a given class. What is even more important, a well designed and well implemented object is able to fulfill a well defined contract. Programming in C++ is about writing contracts and fulfilling them. An interface can, and should, be designed in such a way that the client's part of the contract is simple and well defined. The object may even be able to protect itself from sloppy clients who break their part of the contract. We'll talk about it when we discuss the use of assertions.