Data and behaviour
So far a Dog can hold data: member variables and a constructor give it a name. The other half of object-oriented design is behaviour, the things an object can do. In C++ these actions are member functions, also called methods: functions declared inside a class that work with the data of one object.
Defining a member function
A member function is written like a normal function, but inside the class body:
class Dog {
public:
string name;
Dog(string name) { this->name = name; }
void bark() {
cout << "Woof! I am " << name << endl;
}
};
It has a return type (void here, because it returns nothing), a name, a parameter list and a body. Declaring it after public: makes it callable from outside the class. A function placed under private:, or before any label in a class, can only be called by other members of the class.
Inside the body, name means the member name of the object the function was called on. There is no parameter with that name, so no this-> is needed. Writing this->name would mean exactly the same thing.
Calling it on an object
A member function always runs on a particular object. Call it with the dot operator:
Dog rex("Rex");
Dog luna("Luna");
rex.bark(); // Woof! I am Rex
luna.bark(); // Woof! I am Luna
Both calls run the same code, but each one sees the members of the object before the dot. That is why the output differs. Trying to call bark() with no object, or as Dog::bark(), is a compile error: GCC says it cannot call a member function without an object.
Functions can change state, and can have parameters
A member function can modify the members, take arguments and return values, just like any other function:
class Dog {
public:
string name;
int age = 0;
Dog(string name) { this->name = name; }
void birthday() { age++; }
string describe() const { return name + " is " + to_string(age); }
};
With Dog a("Rex"); and two calls to a.birthday();, the call a.describe() returns "Rex is 2". A second dog's age is not touched, because each object has its own members.
The const after the parameter list is a promise that the function does not modify the object. It is good practice for functions that only read, and it is required if you want to call the function on a const object. This lesson does not need it.
Defining a function outside the class
For longer functions, C++ lets you declare the function inside the class and define it elsewhere. The definition names the class with the scope operator :::
class Dog {
public:
string name;
void bark(); // declaration only
};
void Dog::bark() {
cout << "Woof! I am " << name << endl;
}
The behaviour is the same. Without Dog::, the compiler would treat bark as an unrelated free function that has no name. The lesson keeps everything inside the class, which is the simplest form.
The lesson's exercise
The Dog class has a name and a constructor. The goal is to make rex.bark() in mainFunction work, so the program prints:
Woof! I am Rex
- Below the constructor, still under
public:, declare an empty member functionvoid bark() { }. It returns nothing, so the type isvoid. - In the body, print
"Woof! I am "and thennameusingcout, chaining the pieces with<<, and finish withendlto end the line.
The solution in C++
class Dog {
public:
string name;
Dog(string name) { this->name = name; }
void bark() {
cout << "Woof! I am " << name << endl;
}
};
class Solution {
public:
void mainFunction() {
Dog rex("Rex");
rex.bark();
}
};
The text after Woof! I am comes from the object, not from the function. The string ends with a space on purpose, since cout adds nothing between the pieces it receives.
Common mistakes
- Putting the function outside the class without
Dog::. It then has no access toname. - Leaving it under
private:. The call inmainFunctionthen fails to compile. - Calling it without parentheses.
rex.bark;names the function but doesn't call it, and the compiler reports an invalid use of a non-static member function. - Forgetting the space at the end of
"Woof! I am ", which printsWoof! I amRex. - Using
returnfor printing. The function prints directly and its type isvoid. Returning a string is a different design, where the caller prints.
Key takeaways
- Member functions are functions declared inside a class; they work on the data of the object they are called on.
- Declare them under
public:if outside code should call them. - Inside a member function, a member is used by its bare name, and
this->nameis equivalent. - Call them with the dot operator:
rex.bark();. - A long function can be defined outside the class as
void Dog::bark() { ... }.