跳到主要内容

C++ 成员函数

什么是成员函数?

在C++面向对象编程中,成员函数是定义在类内部的函数,用于操作类的数据成员(属性)并实现类的行为。成员函数是类的一部分,可以访问类的所有成员(包括私有成员),是实现封装原则的重要手段。

成员函数与普通函数的主要区别在于:

  • 成员函数属于特定的类
  • 成员函数可以直接访问类的所有成员
  • 成员函数通过对象来调用(除了静态成员函数)

成员函数的声明与定义

在类内声明和定义

cpp
class Rectangle {
private:
double length;
double width;

public:
// 成员函数在类内声明和定义
void setLength(double l) {
length = l;
}

void setWidth(double w) {
width = w;
}

double getArea() {
return length * width;
}
};

在类外定义

cpp
class Rectangle {
private:
double length;
double width;

public:
// 在类内只声明成员函数
void setLength(double l);
void setWidth(double w);
double getArea();
};

// 在类外定义成员函数
void Rectangle::setLength(double l) {
length = l;
}

void Rectangle::setWidth(double w) {
width = w;
}

double Rectangle::getArea() {
return length * width;
}
备注

在类外定义成员函数时,需要使用作用域解析运算符::来指明该函数属于哪个类。

成员函数的类型

1. 构造函数

构造函数是一种特殊的成员函数,当创建类的新对象时自动调用。它的名称与类名相同,没有返回类型。

cpp
class Person {
private:
string name;
int age;

public:
// 默认构造函数
Person() {
name = "Unknown";
age = 0;
}

// 带参数的构造函数
Person(string n, int a) {
name = n;
age = a;
}
};

2. 析构函数

析构函数在对象被销毁时自动调用,用于释放资源。名称是类名前加上波浪号~,没有参数和返回类型。

cpp
class DynamicArray {
private:
int* array;
int size;

public:
DynamicArray(int s) {
size = s;
array = new int[size]; // 分配动态内存
}

// 析构函数
~DynamicArray() {
delete[] array; // 释放动态分配的内存
}
};

3. 访问器(Getter)和修改器(Setter)

访问器用于获取私有数据成员的值,修改器用于设置私有数据成员的值。

cpp
class Student {
private:
string name;
int id;

public:
// Setter函数
void setName(string n) {
name = n;
}

void setId(int i) {
id = i;
}

// Getter函数
string getName() {
return name;
}

int getId() {
return id;
}
};

4. 常成员函数

常成员函数不能修改类的数据成员(除了被声明为mutable的成员),通过在函数声明后添加关键字const来定义。

cpp
class Circle {
private:
double radius;

public:
Circle(double r) : radius(r) {}

// 常成员函数
double getArea() const {
return 3.14159 * radius * radius;
}
};

5. 静态成员函数

静态成员函数不依赖于特定对象,可以通过类名直接调用,不能访问非静态数据成员。

cpp
class MathUtils {
public:
// 静态成员函数
static int max(int a, int b) {
return (a > b) ? a : b;
}
};

// 使用静态成员函数
int result = MathUtils::max(10, 20); // 输出:20

6. 内联成员函数

内联成员函数在类定义内部定义的成员函数自动成为内联函数,或使用inline关键字显式声明。

cpp
class Calculator {
public:
// 自动内联(在类内定义)
int add(int a, int b) {
return a + b;
}

// 显式内联(在类外定义)
inline int subtract(int a, int b);
};

inline int Calculator::subtract(int a, int b) {
return a - b;
}

成员函数的重载

与普通函数一样,成员函数也可以重载,即同一个类中可以有多个同名但参数列表不同的成员函数。

cpp
class Calculator {
public:
// 成员函数重载
int add(int a, int b) {
return a + b;
}

double add(double a, double b) {
return a + b;
}

int add(int a, int b, int c) {
return a + b + c;
}
};

实际应用案例

让我们通过一个银行账户的例子来展示成员函数的实际应用:

cpp
#include <iostream>
#include <string>
using namespace std;

class BankAccount {
private:
string accountNumber;
string ownerName;
double balance;

public:
// 构造函数
BankAccount(string accNum, string name, double initialBalance) {
accountNumber = accNum;
ownerName = name;
balance = initialBalance;
}

// 存款功能
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "存款成功!当前余额: " << balance << endl;
} else {
cout << "存款金额必须为正数" << endl;
}
}

// 取款功能
bool withdraw(double amount) {
if (amount <= 0) {
cout << "取款金额必须为正数" << endl;
return false;
}

if (amount > balance) {
cout << "余额不足!" << endl;
return false;
}

balance -= amount;
cout << "取款成功!当前余额: " << balance << endl;
return true;
}

// 查询余额
double checkBalance() const {
return balance;
}

// 显示账户信息
void displayInfo() const {
cout << "账号: " << accountNumber << endl;
cout << "户名: " << ownerName << endl;
cout << "余额: " << balance << endl;
}
};

int main() {
// 创建一个银行账户对象
BankAccount myAccount("1001002003", "张三", 1000.0);

// 显示初始账户信息
cout << "===== 初始账户信息 =====" << endl;
myAccount.displayInfo();

// 存款操作
cout << "\n===== 存款操作 =====" << endl;
myAccount.deposit(500.0);

// 取款操作
cout << "\n===== 取款操作 =====" << endl;
myAccount.withdraw(200.0);

// 取款金额过大
cout << "\n===== 尝试取款过大金额 =====" << endl;
myAccount.withdraw(2000.0);

// 查询最终余额
cout << "\n===== 最终账户信息 =====" << endl;
myAccount.displayInfo();

return 0;
}

程序输出:

===== 初始账户信息 =====
账号: 1001002003
户名: 张三
余额: 1000

===== 存款操作 =====
存款成功!当前余额: 1500

===== 取款操作 =====
取款成功!当前余额: 1300

===== 尝试取款过大金额 =====
余额不足!

===== 最终账户信息 =====
账号: 1001002003
户名: 张三
余额: 1300

成员函数与this指针

每个非静态成员函数都有一个隐含的this指针,指向调用该成员函数的对象。尽管我们很少显式使用this指针,但了解它的存在有助于理解成员函数的工作方式。

cpp
class Counter {
private:
int count;

public:
Counter() : count(0) {}

// 使用this指针的成员函数
Counter& increment() {
this->count++; // 等同于 count++
return *this; // 返回对象自身的引用
}

void display() {
cout << "Count: " << count << endl;
}
};

int main() {
Counter c;
// 链式调用
c.increment().increment().display(); // 输出: Count: 2
return 0;
}
提示

使用this指针返回对象的引用可以实现链式调用,这是很多C++库的常见设计模式。

内联成员函数的优缺点

内联成员函数可以提高程序的执行效率,因为它避免了函数调用的开销,但也会增加程序的体积。

优点:

  • 减少函数调用的开销
  • 提高执行效率,尤其是对于小型、频繁调用的函数

缺点:

  • 增加编译后程序的体积
  • 过度使用可能导致指令缓存效率降低
  • 复杂函数不适合内联
警告

内联只是对编译器的建议,编译器可能会忽略内联请求,尤其是对于复杂的函数。

成员函数的访问控制

成员函数的访问权限与数据成员类似,可以是公有(public)、私有(private)或保护(protected)的:

cpp
class AccessExample {
private:
void privateFunction() {
cout << "这是私有成员函数" << endl;
}

protected:
void protectedFunction() {
cout << "这是保护成员函数" << endl;
}

public:
void publicFunction() {
cout << "这是公有成员函数" << endl;
// 私有和保护成员函数可以在类内调用
privateFunction();
protectedFunction();
}
};

总结

成员函数是C++面向对象编程的核心概念之一,它们:

  1. 定义了类的行为和功能
  2. 可以访问类的所有成员
  3. 实现了数据封装的原则
  4. 有多种类型,包括构造函数、析构函数、常成员函数等
  5. 可以在类内或类外定义
  6. 可以重载以提供更灵活的功能

掌握成员函数的使用是学习C++面向对象编程的关键步骤,它为理解更复杂的概念如继承和多态打下了坚实的基础。

练习题

  1. 创建一个Time类,包含小时、分钟和秒属性,并编写成员函数来设置时间、显示时间,以及计算两个时间对象之间的差值。

  2. 设计一个String类,实现基本的字符串操作功能,包括字符串连接、求长度、比较等操作。

  3. 创建一个Stack类实现栈的基本操作(push、pop、peek等),并使用动态数组作为内部存储结构。

  4. 实现一个Complex类表示复数,并定义加、减、乘等操作的成员函数。

备注

尝试解决上述练习题将帮助你更好地理解和应用成员函数的概念。