What are Member Functions?
Member functions are functions that are declared within a class and operate on objects of that class. They can access the private and protected members of the class and define the behavior of class objects.
Ways to Define Member Functions
There are two main ways to define member functions in C++:
- Inside the class definition (inline by default)
- Outside the class definition (using the scope resolution operator
::)
Defining Member Functions Inside the Class
When member functions are defined inside the class, they are automatically considered inline functions (though the compiler makes the final decision on inlining).
class Rectangle {
private:
double length;
double width;
public:
// Member function defined inside the class
void setDimensions(double l, double w) {
length = l;
width = w;
}
// Another member function defined inside the class
double calculateArea() {
return length * width;
}
};
Defining Member Functions Outside the Class
For larger functions or to separate the interface from the implementation, member functions can be defined outside the class using the scope resolution operator ::.
class Circle {
private:
double radius;
public:
// Function declarations (prototypes)
void setRadius(double r);
double getRadius();
double calculateArea();
double calculateCircumference();
};
// Function definitions outside the class
void Circle::setRadius(double r) {
radius = r;
}
double Circle::getRadius() {
return radius;
}
double Circle::calculateArea() {
return 3.14159 * radius * radius;
}
double Circle::calculateCircumference() {
return 2 * 3.14159 * radius;
}
Member Function Types
1. Constructor Functions
Constructors are special member functions that are called when an object is created. They have the same name as the class and no return type.
class Student {
private:
string name;
int rollNumber;
public:
// Default constructor
Student() {
name = "Unknown";
rollNumber = 0;
}
// Parameterized constructor
Student(string n, int r) {
name = n;
rollNumber = r;
}
};
2. Destructor Functions
Destructors are called when an object is destroyed. They have the same name as the class preceded by a tilde (~) and no return type.
class DynamicArray {
private:
int* array;
int size;
public:
// Constructor
DynamicArray(int s) {
size = s;
array = new int[size];
}
// Destructor
~DynamicArray() {
delete[] array; // Free the allocated memory
}
};
3. Accessor Functions (Getters)
Accessors retrieve the values of private data members without modifying them.
class Person {
private:
string name;
int age;
public:
// Constructor
Person(string n, int a) {
name = n;
age = a;
}
// Accessor (getter) functions
string getName() {
return name;
}
int getAge() {
return age;
}
};
4. Mutator Functions (Setters)
Mutators modify the values of private data members, often with validation.
class BankAccount {
private:
string accountNumber;
double balance;
public:
// Constructor
BankAccount(string accNum) {
accountNumber = accNum;
balance = 0.0;
}
// Mutator (setter) function with validation
void deposit(double amount) {
if (amount > 0) {
balance += amount;
} else {
cout << "Invalid deposit amount!" << endl;
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
} else {
cout << "Invalid withdrawal or insufficient funds!" << endl;
}
}
};
5. Const Member Functions
Const member functions cannot modify the object’s state and can be called on const objects.
class Circle {
private:
double radius;
public:
Circle(double r) {
radius = r;
}
// Const member function
double getRadius() const {
return radius;
}
double calculateArea() const {
return 3.14159 * radius * radius;
}
};
Usage example:
void printArea(const Circle& circle) {
// This is valid because calculateArea() is a const member function
cout << "Area: " << circle.calculateArea() << endl;
}
6. Static Member Functions
Static member functions belong to the class as a whole, not to individual objects. They can only access static members of the class.
class MathUtils {
private:
static int operationCount;
public:
static double square(double num) {
operationCount++;
return num * num;
}
static double cube(double num) {
operationCount++;
return num * num * num;
}
static int getOperationCount() {
return operationCount;
}
};
// Initialize static member
int MathUtils::operationCount = 0;
Usage example:
double result1 = MathUtils::square(5.0); // Called without an object
double result2 = MathUtils::cube(3.0);
cout << "Operations performed: " << MathUtils::getOperationCount() << endl;
7. Friend Functions
Friend functions are not member functions, but they have access to private and protected members of a class.
class Box {
private:
double length;
double width;
double height;
public:
Box(double l, double w, double h) {
length = l;
width = w;
height = h;
}
// Declaration of a friend function
friend double calculateVolume(const Box& box);
};
// Definition of the friend function
double calculateVolume(const Box& box) {
// Can access private members because it's a friend
return box.length * box.width * box.height;
}
Using the this Pointer
The this pointer is an implicit parameter that points to the current object. It can be used to:
- Refer to the current object
- Resolve name conflicts
- Return the current object (for method chaining)
class Counter {
private:
int count;
public:
Counter(int count = 0) {
// Using this pointer to resolve name conflict
this->count = count;
}
// Return reference to the current object for method chaining
Counter& increment() {
count++;
return *this;
}
Counter& decrement() {
count--;
return *this;
}
int getCount() {
return count;
}
};
Usage example:
Counter c(5);
c.increment().increment().decrement(); // Method chaining
cout << "Count: " << c.getCount() << endl; // Output: 6
Function Overloading in Classes
Classes can have multiple member functions with the same name but different parameters (function overloading).
class PrintUtil {
public:
void print(int num) {
cout << "Integer: " << num << endl;
}
void print(double num) {
cout << "Double: " << num << endl;
}
void print(string text) {
cout << "String: " << text << endl;
}
};
Usage example:
PrintUtil printer;
printer.print(10); // Calls print(int)
printer.print(10.5); // Calls print(double)
printer.print("Hello"); // Calls print(string)
Default Arguments in Member Functions
Member functions can have default arguments that are used when the caller doesn’t provide them.
class Message {
private:
string text;
public:
Message(string t = "") {
text = t;
}
void display(string prefix = "Message: ", bool newline = true) {
cout << prefix << text;
if (newline) {
cout << endl;
}
}
};
Usage example:
Message msg("Hello World");
msg.display(); // Uses both defaults
msg.display("Text: "); // Custom prefix, default newline
msg.display("Content: ", false); // Custom for both parameters
Inline Member Functions
Member functions defined inside the class are implicitly inline. For functions defined outside, you can explicitly use the inline keyword.
class Timer {
private:
int seconds;
public:
// Implicitly inline (defined inside the class)
void setSeconds(int s) {
seconds = s;
}
// Function declaration
int getMinutes();
};
// Explicitly inline function defined outside the class
inline int Timer::getMinutes() {
return seconds / 60;
}
Best Practices for Member Functions
- Keep functions focused: Each function should do one thing well
- Make functions short and clear: Long functions are harder to understand
- Use meaningful names: Names should describe what the function does
- Use const where appropriate: Mark functions that don’t modify the object as const
- Validate input: Check parameters in setter functions
- Handle errors appropriately: Return error codes or throw exceptions
- Consider the interface carefully: Design a clean and intuitive API
- Document your functions: Use comments to explain complex logic
Example: Complete Class with Various Member Functions
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
string accountNumber;
string ownerName;
double balance;
static double interestRate;
public:
// Constructors
BankAccount() : accountNumber(""), ownerName(""), balance(0.0) {}
BankAccount(string accNum, string name, double initialBalance = 0.0) {
accountNumber = accNum;
ownerName = name;
if (initialBalance >= 0) {
balance = initialBalance;
} else {
balance = 0.0;
cout << "Warning: Initial balance cannot be negative. Set to 0." << endl;
}
}
// Destructor
~BankAccount() {
cout << "Account " << accountNumber << " destroyed." << endl;
}
// Accessor functions (getters)
string getAccountNumber() const {
return accountNumber;
}
string getOwnerName() const {
return ownerName;
}
double getBalance() const {
return balance;
}
// Mutator functions (setters)
void setOwnerName(string name) {
ownerName = name;
}
// Member functions for account operations
bool deposit(double amount) {
if (amount > 0) {
balance += amount;
return true;
}
return false;
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
void applyInterest() {
balance += balance * interestRate;
}
void displayInfo() const {
cout << "Account Information:" << endl;
cout << "Account Number: " << accountNumber << endl;
cout << "Owner: " << ownerName << endl;
cout << "Balance: $" << balance << endl;
}
// Static member function
static void setInterestRate(double rate) {
if (rate >= 0) {
interestRate = rate;
}
}
static double getInterestRate() {
return interestRate;
}
// Friend function
friend void auditAccount(const BankAccount& account);
};
// Initialize static member
double BankAccount::interestRate = 0.03; // 3% interest rate
// Friend function definition
void auditAccount(const BankAccount& account) {
cout << "AUDIT - Account: " << account.accountNumber
<< ", Owner: " << account.ownerName
<< ", Balance: $" << account.balance << endl;
}
int main() {
// Creating objects
BankAccount acc1("AC001", "John Doe", 1000.0);
BankAccount acc2("AC002", "Jane Smith", 2500.0);
// Using member functions
acc1.deposit(500.0);
acc2.withdraw(300.0);
// Using static member function
BankAccount::setInterestRate(0.04); // Change interest rate to 4%
// Apply interest to all accounts
acc1.applyInterest();
acc2.applyInterest();
// Display information
acc1.displayInfo();
acc2.displayInfo();
// Using friend function
auditAccount(acc1);
return 0;
}
Summary
Member functions define the behavior of objects in C++ classes. They can be defined inside or outside the class definition and can have various characteristics such as being constructors, destructors, accessors, mutators, const functions, static functions, or inline functions. Understanding how to properly define and use member functions is essential for effective object-oriented programming in C++.