Lesson 2 of 12
A member function is a function that belongs to a type and can see its data without being handed it.
#include <iostream>
class Counter {
int count = 0; // default member initialiser
public:
void increment() { ++count; } // sees `count` directly
void reset() { count = 0; }
int value() const { return count; }
};
int main() {
Counter c;
c.increment();
c.increment();
c.increment();
std::cout << c.value() << "\n";
c.reset();
std::cout << c.value() << "\n";
return 0;
}
3
0
increment() never receives count as a parameter. Every member function has an implicit
reference to the object it was called on, which lesson 9.5 makes explicit as this.
Default member initialisers
int count = 0; inside the class gives every Counter a starting value without writing a
constructor. Prefer this: an uninitialised member is the class-shaped version of lesson 3.1's
garbage variable.
#include <iostream>
#include <string>
struct Config {
std::string host = "localhost";
int port = 8080;
bool verbose = false;
};
int main() {
Config c;
std::cout << c.host << ":" << c.port << " verbose=" << c.verbose << "\n";
Config custom;
custom.port = 9090;
std::cout << custom.host << ":" << custom.port << "\n";
return 0;
}
localhost:8080 verbose=0
localhost:9090
const member functions
A member function marked const promises not to modify the object:
#include <iostream>
class Temperature {
double celsius = 0.0;
public:
void set(double c) { celsius = c; } // modifies: not const
double get() const { return celsius; } // reads only: const
double fahrenheit() const { return celsius * 9.0 / 5.0 + 32.0; }
// Trying to write to a member inside a const function is an error:
// double bad() const { celsius = 1.0; return celsius; }
// error: assignment of member 'Temperature::celsius' in read-only object
};
int main() {
Temperature t;
t.set(100.0);
std::cout << t.get() << "C = " << t.fahrenheit() << "F\n";
return 0;
}
100C = 212F
The const goes after the parameter list, which is unusual-looking but consistent: it applies
to the implicit object parameter, not to the return value.
Why const matters more than it looks
A const object can only call const member functions:
#include <iostream>
class Box {
int value = 7;
public:
int get() const { return value; }
void set(int v) { value = v; }
};
void inspect(const Box& b) {
std::cout << b.get() << "\n"; // fine: get() is const
// b.set(1); // error: passing 'const Box' as 'this'
// discards qualifiers
}
int main() {
Box b;
inspect(b);
const Box frozen;
std::cout << frozen.get() << "\n"; // only const members are callable
return 0;
}
7
7
This is why forgetting const spreads: a member function that could be const but is not cannot
be called on a const object, so callers are forced to drop const too, and the guarantee
unravels through the codebase.
Mark every member function const that does not modify the object. It costs nothing and is
tedious to retrofit.
Defining members outside the class
Long functions clutter a class definition. Define them outside with ClassName:::
#include <iostream>
class Rectangle {
double width = 0.0;
double height = 0.0;
public:
void set_size(double w, double h);
double area() const;
double perimeter() const;
};
void Rectangle::set_size(double w, double h) {
width = (w < 0.0) ? 0.0 : w;
height = (h < 0.0) ? 0.0 : h;
}
double Rectangle::area() const {
return width * height;
}
double Rectangle::perimeter() const {
return 2.0 * (width + height);
}
int main() {
Rectangle r;
r.set_size(3.0, 4.0);
std::cout << r.area() << " " << r.perimeter() << "\n";
return 0;
}
12 14
Note the const must appear in both the declaration and the definition — they are part of
the signature. Omitting it in one place produces a confusing "no declaration matches" error.
This split is what header files are for (lesson 5.8): the class definition goes in the .hpp, the
member function bodies in the .cpp.
Members defined inside are implicitly inline
A member function whose body is inside the class body is implicitly inline, which is why you can
put it in a header without violating the one-definition rule. A member defined outside the class
in a header needs an explicit inline, or it belongs in a .cpp.
Try it
Write a class BankAccount with a private balance, and deposit, withdraw, and balance
members. withdraw should refuse to overdraw. Mark everything const that can be, then try
calling each member on a const BankAccount&.
Checkpoint
- A member function belongs to the type and accesses its members without parameters.
- Default member initialisers (
int count = 0;) prevent uninitialised members. constafter the parameter list promises the function does not modify the object.- A
constobject can only callconstmember functions, so missingconstspreads. - Members can be defined outside the class with
Type::name;constmust match in both places. - Bodies written inside the class are implicitly
inline.
Questions about this lesson
Log in to ask a question.