Classes and Objects

Declaring and Calling Member Functions

Member functions are standard function members that you place within a class to make them part of the type. Member functions can be invoked on objects of a given class and may access the data members of the object which invoked them while in execution.

The easiest way to define a member function is to implement its full definition within the class body as shown below. This example program defines a class which stores a single integer and provides a member function to increment the integer by one.

#include <iostream>

class Counter
{
private:
    int value{};

public:
    void increase()
    {
        ++value;
    }

    void print()
    {
        std::cout << value << '\n';
    }
};

int main()
{
    Counter c{};
    c.increase();
    c.increase();
    c.print();

    // Return the computed value to the caller
    return 0;
}

The class Counter stores a single private data member value; in the subsequent two public member functions. The member function increase takes no parameters and returns no value; its function body increments the data member. The function print similarly takes no parameters, and sends the data member to the output; and, since it's defined within the class body, it's permissible for the function print to refer to the private data member value.

An object c is instantiated within main. Its member function increase is invoked via the statement; this object invocation consists of two parts, the object that will be the target, and then the member function itself. The syntax for invocation uses a dot operator between the object that will be invoked, and the target member function.

When the member function is executed, the identifier value refers to the data member that is owned by the object c.

The second call to increase thus operates upon the already incremented value, and increments it further. The final call to print within main will print an output of 2.

Member functions can have parameters and return values, which is illustrated in the example below by keeping track of a width and a height, and using a member function to calculate the area.

#include <iostream>

class Rectangle
{
private:
    double width{};
    double height{};

public:
    void set(double w, double h)
    {
        // Require both conditions joined by logical AND to be true
        if (w > 0.0 && h > 0.0)
        {
            width = w;
            height = h;
        }
    }

    double area()
    {
        return width * height;
    }
};

int main()
{
    Rectangle r{};
    r.set(3.0, 4.0);
    std::cout << r.area() << '\n';

    return 0;
}

The data members width and height are initialized to zero; the public member function set accepts two double arguments, validating that they are positive before assigning them to the data members. The public member function area takes no parameters and returns the calculated area as a double. Inside main, object r is constructed, using the set function to set its values and then utilizing the area member function, its return value is printed, resulting in an output of 12.

The object invoked, on the left side of the dot, is a critical part of function invocation. Every member function call will act upon an object, this object being expressed by the left hand operand to the call. Simply writing just the name of the member function or the name of the class and the name of the member function will result in a compile time error because the compiler will not know which specific piece of data the member function should use while operating. Using two objects, they act independently with regard to the actions performed upon them:

#include <iostream>

class Counter
{
private:
    int value{};

public:
    void increase()
    {
        // Increment the value before the expression uses it
        ++value;
    }

    void print()
    {
        std::cout << value << '\n';
    }
};

int main()
{
    Counter first{};
    Counter second{};

    first.increase();
    first.increase();
    second.increase();

    first.print();
    second.print();

    return 0;
}

The object first now contains the data member value of 2, while the object second stores data member value of 1. The two print functions output these differences accordingly; the data associated with either object cannot be modified by an interaction with the other object.

When the member function is declared within the class body, no further adornments are needed to use the data members within the body. The compiler deduces which objects are appropriate from the fact that the member function is a member of a particular class. This means we do not need to precede the data members by object names, such as in the previous two examples, when defining or invoking them within the function body.

A program still compiles, even if a member function was declared and never called. But a call that specifies the wrong number or types for arguments is identified by the compiler and the program does not compile. Specifying a member function with nothing after the name is an error, for example, attempting to invoke the function c.increase, not c.increase(), the function name alone is simply not enough, since one or more arguments may be required when an object is invoked.

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.