C++学习笔记——友元及重载运算符
目录
一、友元
在 C++ 中,友元是一个函数或类,它可以访问另一个类的私有成员或保护成员。通常情况下,我们在类定义中声明友元函数或友元类,以便它们能够访问类的私有成员。友元可以是一个函数、类、或整个命名空间。
1.1声明友元函数
首先,我们来看一下如何声明友元函数。假设我们有一个 Box
类,它表示一个三维立方体:
class Box {
public:
Box(double l, double w, double h) : length(l), width(w), height(h) {}
private:
double length;
double width;
double height;
};
我们想要计算一个 Box
对象的体积,但是 length
、width
和 height
都是私有成员,无法在类外直接访问。这时候,我们可以使用友元函数来实现。我们可以在类定义中声明一个友元函数,并将其定义为一个全局函数:
class Box {
public:
Box(double l, double w, double h) : length(l), width(w), height(h) {}
friend double getVolume(Box box);
private:
double length;
double width;
double height;
};
double getVolume(Box box) {
return box.length * box.width * box.height;
}
在上面的代码中,我们在 Box
类定义中声明了一个友元函数 getVolume()
,并将其定义为一个全局函数。在 getVolume()
函数中,我们可以直接访问 Box
类的私有成员 length
、width
和 height
,计算出它的体积并返回。
1.2声明友元类
除了友元函数,我们还可以声明友元类。假设我们有一个 Stack
类,它表示一个栈:
template <typename T>
class Stack {
public:
Stack() : top(-1) {}
private:
T data[10];
int top;
friend class StackIterator<T>;
};
我们想要实现一个迭代器类来遍历栈中的元素。但是,由于 data
和 top
都是私有成员,无法在迭代器类中直接访问。这时候,我们可以声明 StackIterator
类为 Stack
类的友元类:
template <typename T>
class StackIterator {
public:
StackIterator(Stack<T>& s) : stack(s), index(s.top) {}
T next() {
return stack.data[index--];
}
private:
Stack<T>& stack;
int index;
};
template <typename T>
class Stack {
public:
Stack() : top(-1) {}
friend class StackIterator<T>;
private:
T data[10];
int top;
};
在上面的代码中,我们声明了一个友元类 StackIterator
,并在 Stack
类定义中将其声明为友元类。在 StackIterator
类中,我们可以直接访问 Stack
类的私有成员 data
和 top
,实现了对栈的迭代。
二、运算符重载
C++ 中有一些运算符是可以被重载的,比如加号、减号、乘号、除号等等。通过重载运算符,我们可以改变它的行为,使其能够作用于我们自定义的类型。
2.1重载加号运算符
假设我们有一个 Complex
类,它表示一个复数:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
private:
double real;
double imag;
};
我们想要实现复数的加法运算,但是加号运算符无法直接作用于自定义的类型。这时候,我们可以重载加号运算符 +
,使其能够对两个 Complex
对象进行相加,并返回一个新的 Complex
对象:
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
private:
double real;
double imag;
};
在上面的代码中,我们重载了加号运算符 +
,并定义了一个成员函数 operator+()
。在函数中,我们定义了一个新的 Complex
对象,其实部为两个复数的实部相加,虚部为两个复数的虚部相加,并将其返回。
2.2重载流插入运算符
除了加号运算符,我们还可以重载其他运算符。比如,我们可以重载流插入运算符 <<
,使其能够输出我们自定义的类型。假设我们有一个 Person
类,它表示一个人:
#include <iostream>
#include <string>
class Person {
public:
Person(std::string n, int a) : name(n), age(a) {}
friend std::ostream& operator<<(std::ostream& os, const Person& p);
private:
std::string name;
int age;
};
std::ostream& operator<<(std::ostream& os, const Person& p) {
os << "Name: " << p.name << ", Age: " << p.age;
return os;
}
int main() {
Person p("Alice", 20);
std::cout << p << std::endl;
return 0;
}
在上面的代码中,我们重载了流插入运算符 <<
,并将其定义为一个友元函数。在函数中,我们将 Person
对象的姓名和年龄输出到标准输出流 os
中,然后返回该流。在主函数中,我们创建了一个 Person
对象 p
,并使用 <<
运算符将其输出到标准输出流中。
需要注意的是,在重载运算符时需要遵循一些规则。比如,我们必须使用正确的参数类型和返回值类型,以及保证运算符的语义符合预期。此外,C++ 中还存在一些运算符是无法被重载的,比如条件运算符 ?:
,作用域运算符 ::
等等。
三、一个简单的银行管理系统
#include <iostream>
#include <string>
#include <vector>
class Account {
public:
Account(std::string name, std::string accountNumber, double balance)
: name(name), accountNumber(accountNumber), balance(balance) {}
void deposit(double amount) {
balance += amount;
std::cout << "Deposit successful. New balance: " << balance << std::endl;
}
void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
std::cout << "Withdrawal successful. New balance: " << balance << std::endl;
} else {
std::cout << "Insufficient balance." << std::endl;
}
}
void displayInfo() {
std::cout << "Name: " << name << std::endl;
std::cout << "Account Number: " << accountNumber << std::endl;
std::cout << "Balance: " << balance << std::endl;
}
private:
std::string name;
std::string accountNumber;
double balance;
};
class Bank {
public:
void createAccount(std::string name, std::string accountNumber, double balance) {
Account account(name, accountNumber, balance);
accounts.push_back(account);
std::cout << "Account created successfully." << std::endl;
}
void deposit(std::string accountNumber, double amount) {
Account* account = findAccount(accountNumber);
if (account != nullptr) {
account->deposit(amount);
} else {
std::cout << "Account not found." << std::endl;
}
}
void withdraw(std::string accountNumber, double amount) {
Account* account = findAccount(accountNumber);
if (account != nullptr) {
account->withdraw(amount);
} else {
std::cout << "Account not found." << std::endl;
}
}
void displayAllAccounts() {
for (const auto& account : accounts) {
account.displayInfo();
std::cout << "---------------------------" << std::endl;
}
}
private:
std::vector<Account> accounts;
Account* findAccount(std::string accountNumber) {
for (auto& account : accounts) {
if (account.getAccountNumber() == accountNumber) {
return &account;
}
}
return nullptr;
}
};
int main() {
Bank bank;
int choice;
do {
std::cout << "1. Create Account" << std::endl;
std::cout << "2. Deposit" << std::endl;
std::cout << "3. Withdraw" << std::endl;
std::cout << "4. Display All Accounts" << std::endl;
std::cout << "5. Exit" << std::endl;
std::cout << "Enter your choice: ";
std::cin >> choice;
if (choice == 1) {
std::string name, accountNumber;
double balance;
std::cout << "Enter name: ";
std::cin >> name;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter initial balance: ";
std::cin >> balance;
bank.createAccount(name, accountNumber, balance);
} else if (choice == 2) {
std::string accountNumber;
double amount;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter amount to deposit: ";
std::cin >> amount;
bank.deposit(accountNumber, amount);
} else if (choice == 3) {
std::string accountNumber;
double amount;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter amount to withdraw: ";
std::cin >> amount;
bank.withdraw(accountNumber, amount);
} else if (choice == 4) {
bank.displayAllAccounts();
}
} while (choice != 5);
return 0;
}
在上面的代码中,我们定义了两个类:Account
和 Bank
。Account
类代表一个银行账户,具有姓名、账号和余额属性,以及存款、取款和展示信息的方法。Bank
类代表整个银行系统,具有创建账户、存款、取款和显示所有账户的方法。其中,存款和取款的操作会调用 Account
类相应的方法。
在主函数中,我们通过简单的菜单来模拟用户与银行系统的交互。用户可以选择创建账户、存款、取款或显示所有账户的操作,直到选择退出。
四、 详细的介绍
以下是代码中每个部分的更详细解释:
class Account {
public:
Account(std::string name, std::string accountNumber, double balance)
: name(name), accountNumber(accountNumber), balance(balance) {}
在 Account
类的构造函数中,我们使用传入的参数来初始化私有成员变量 name
、accountNumber
和 balance
。
void deposit(double amount) {
balance += amount;
std::cout << "Deposit successful. New balance: " << balance << std::endl;
}
deposit
方法用于存款操作。它接受一个 double 类型的参数 amount
,代表要存入的金额。方法内部,我们将传入的金额加到余额上,并输出新的余额。
void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
std::cout << "Withdrawal successful. New balance: " << balance << std::endl;
} else {
std::cout << "Insufficient balance." << std::endl;
}
}
withdraw
方法用于取款操作。它接受一个 double 类型的参数 amount
,代表要取出的金额。方法内部,我们首先检查账户余额是否足够,如果足够就从余额中减去取款金额,并输出新的余额。如果余额不足,则输出错误信息。
void displayInfo() {
std::cout << "Name: " << name << std::endl;
std::cout << "Account Number: " << accountNumber << std::endl;
std::cout << "Balance: " << balance << std::endl;
}
displayInfo
方法用于展示账户的信息。它输出账户的姓名、账号和余额。
class Bank {
public:
void createAccount(std::string name, std::string accountNumber, double balance) {
Account account(name, accountNumber, balance);
accounts.push_back(account);
std::cout << "Account created successfully." << std::endl;
}
createAccount
方法用于创建一个新的账户。它接受三个参数:姓名、账号和初始余额。方法内部,我们创建一个新的 Account
对象,并将其添加到 accounts
列表中。然后,我们输出成功创建账户的消息。
void deposit(std::string accountNumber, double amount) {
Account* account = findAccount(accountNumber);
if (account != nullptr) {
account->deposit(amount);
} else {
std::cout << "Account not found." << std::endl;
}
}
deposit
方法用于给指定账户存款。它接受两个参数:账户号码和存款金额。方法内部,我们通过调用 findAccount
方法来查找要操作的账户。如果找到了账户,则调用该账户的 deposit
方法执行存款操作。如果未找到账户,则输出错误信息。
void withdraw(std::string accountNumber, double amount) {
Account* account = findAccount(accountNumber);
if (account != nullptr) {
account->withdraw(amount);
} else {
std::cout << "Account not found." << std::endl;
}
}
withdraw
方法用于给指定账户取款。它接受两个参数:账户号码和取款金额。方法内部,我们通过调用 findAccount
方法来查找要操作的账户。如果找到了账户,则调用该账户的 withdraw
方法执行取款操作。如果未找到账户,则输出错误信息。
void displayAllAccounts() {
for (const auto& account : accounts) {
account.displayInfo();
std::cout << "---------------------------" << std::endl;
}
}
displayAllAccounts
方法用于展示银行中所有账户的信息。它遍历 accounts
列表,并对每个账户调用 displayInfo
方法来输出信息。在每个账户信息输出之后,我们打印分隔线以区分不同的账户。
int main() {
Bank bank;
int choice;
do {
std::cout << "1. Create Account" << std::endl;
std::cout << "2. Deposit" << std::endl;
std::cout << "3. Withdraw" << std::endl;
std::cout << "4. Display All Accounts" << std::endl;
std::cout << "5. Exit" << std::endl;
std::cout << "Enter your choice: ";
std::cin >> choice;
if (choice == 1) {
std::string name, accountNumber;
double balance;
std::cout << "Enter name: ";
std::cin >> name;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter initial balance: ";
std::cin >> balance;
bank.createAccount(name, accountNumber, balance);
} else if (choice == 2) {
std::string accountNumber;
double amount;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter amount to deposit: ";
std::cin >> amount;
bank.deposit(accountNumber, amount);
} else if (choice == 3) {
std::string accountNumber;
double amount;
std::cout << "Enter account number: ";
std::cin >> accountNumber;
std::cout << "Enter amount to withdraw: ";
std::cin >> amount;
bank.withdraw(accountNumber, amount);
} else if (choice == 4) {
bank.displayAllAccounts();
}
} while (choice != 5);
return 0;
}
在 main
函数中,我们使用一个循环来模拟用户与银行系统的交互。我们显示一个简单的菜单,让用户选择不同的操作。根据用户的选择,我们调用 Bank
类的相应方法来执行操作。当用户选择退出时,循环结束,程序终止。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!