目录标题
- 1. 什么是类?
- 2. 什么是对象?
- 3. 如何定义一个类?
- 4. 如何创建对象?
- 5. 类的构造函数
- 6. 类的析构函数
- 7. 数据封装和访问修饰符
- 8. 示例:一个简单的`BankAccount`类
- 9. 使用g++编译
- 10. 再来一个简单的C++程序
- 11. 定义书籍类 `Book`
- 12. 实现书籍类的成员函数
- 13. 使用书籍类
- 14. 编译和运行
- 15. 再来一个例子
- 16. 定义账户类 `Account`
- 17. 实现账户类 `Account`
- 18. 定义银行类 `Bank`
- 19. 实现银行类 `Bank`
- 20. 使用`Account`和`Bank`类
- 21. 编译和运行
- 22. 拓展:std::string getTitle() const; 这里的std是什么意思?
面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它使用“对象”来设计软件。在C++中,对象是通过类来创建的。类是创建对象的蓝图或模板。
1. 什么是类?
类是一种用户定义的数据类型,它拥有数据成员和成员函数。数据成员用于存储与类相关的信息,而成员函数则用于操作这些数据。类可以看作创建对象的模板。
2. 什么是对象?
对象是类的实例。一旦定义了类,我们可以通过类创建对象,对象包含了类中定义的数据成员和成员函数。
3. 如何定义一个类?
C++中类的定义以关键字class
开始,后跟类名和类体。类体包含在一对花括号中。通常,类的定义会放在头文件中,例如.h
或.hpp
文件。
// BankAccount.h
class BankAccount {
public:
// 构造函数
BankAccount(double balance);
// 成员函数
void deposit(double amount);
void withdraw(double amount);
double getBalance() const;
private:
// 数据成员
double balance;
};
4. 如何创建对象?
创建类的对象非常简单,只需像声明普通变量一样声明对象即可。
BankAccount myAccount(50.0);
5. 类的构造函数
构造函数是一种特殊的成员函数,它在创建对象时自动调用。构造函数的名称与类名相同。
// BankAccount.cpp
BankAccount::BankAccount(double initialBalance) : balance(initialBalance) {
if (initialBalance < 0) {
balance = 0;
// 报告错误:初始余额不能为负
}
}
6. 类的析构函数
析构函数是另一种特殊的成员函数,它在对象销毁时自动调用。析构函数的名称是在类名前加上一个波浪号~
。
7. 数据封装和访问修饰符
封装是面向对象编程的一个重要特征,它防止了对对象内部的直接访问。在C++中,我们通过访问修饰符public
、protected
和private
来实现封装。
8. 示例:一个简单的BankAccount
类
让我们来看一个完整的例子,它定义了一个BankAccount
类和相关的成员函数。
// BankAccount.h
class BankAccount {
public:
BankAccount(double balance);
void deposit(double amount);
void withdraw(double amount);
double getBalance() const;
private:
double balance;
};
// BankAccount.cpp
#include "BankAccount.h"
BankAccount::BankAccount(double initialBalance) : balance(initialBalance) {
if (initialBalance < 0) {
balance = 0;
// 报告错误:初始余额不能为负
}
}
void BankAccount::deposit(double amount) {
if (amount > 0) {
balance += amount;
} else {
// 报告错误:存款金额必须大于0
}
}
void BankAccount::withdraw(double amount) {
if (amount > balance) {
// 报告错误:不能透支账户
} else {
balance -= amount;
}
}
double BankAccount::getBalance() const {
return balance;
}
// main.cpp
#include <iostream>
#include "BankAccount.h"
int main() {
BankAccount myAccount(100.0);
myAccount.deposit(50.0);
myAccount.withdraw(25.0);
std::cout << "当前余额: $" << myAccount.getBalance() << std::endl;
return 0;
}
在这个例子中,我们创建了一个BankAccount
类,它有一个构造函数,两个操作余额的函数deposit
和withdraw
,以及一个查询余额的函数getBalance
。这个类的私有数据成员balance
用于存储账户余额。
9. 使用g++编译
要使用g++
编译上述示例,需要确保所有的源文件(.cpp
)和头文件(.h
)都在同一个目录下。
- 使用
g++
编译器编译BankAccount.cpp
和main.cpp
文件。
g++ -c BankAccount.cpp
g++ -c main.cpp
这两个命令分别编译了BankAccount.cpp
和main.cpp
文件,并生成了对应的目标文件(.o
文件)。
- 接下来,链接这些目标文件以生成最终的可执行文件。使用以下命令:
g++ BankAccount.o main.o -o BankAccountApp
这个命令将BankAccount.o
和main.o
文件链接在一起,并创建了一个名为BankAccountApp
的可执行文件。
- 运行生成的可执行文件:
./BankAccountApp
如果一切顺利,应该会看到程序输出的当前余额。
完整的编译和运行命令序列如下:
g++ -c BankAccount.cpp
g++ -c main.cpp
g++ BankAccount.o main.o -o BankAccountApp
./BankAccountApp
当前余额: $125
如果希望一步完成编译和链接,可以使用以下命令:
g++ BankAccount.cpp main.cpp -o BankAccountApp
这个命令会同时编译和链接所有的.cpp
文件,并生成一个名为BankAccountApp
的可执行文件。然后,可以运行这个可执行文件来查看程序的输出。
10. 再来一个简单的C++程序
再创建一个简单的C++程序,这次我们将实现一个书籍类(Book
)。这个类将包含一些基本属性,如标题、作者和出版年份,并提供一些成员函数来访问和修改这些属性。
11. 定义书籍类 Book
首先,我们将定义一个名为 Book
的类,它将具有三个私有成员:标题(title
)、作者(author
)和出版年份(publishYear
)。我们还将提供公共函数来构造书籍、设置和获取这些属性。
// Book.h
#ifndef BOOK_H
#define BOOK_H
#include <string>
class Book {
public:
// 构造函数
Book(const std::string& title, const std::string& author, int publishYear);
// 成员函数
void setTitle(const std::string& title);
void setAuthor(const std::string& author);
void setPublishYear(int year);
std::string getTitle() const;
std::string getAuthor() const;
int getPublishYear() const;
private:
std::string title;
std::string author;
int publishYear;
};
#endif
12. 实现书籍类的成员函数
接下来,我们实现这个类的成员函数。这些函数包括构造函数、设置和获取属性的函数。
// Book.cpp
#include "Book.h"
Book::Book(const std::string& title, const std::string& author, int publishYear)
: title(title), author(author), publishYear(publishYear) {}
void Book::setTitle(const std::string& title) {
this->title = title;
}
void Book::setAuthor(const std::string& author) {
this->author = author;
}
void Book::setPublishYear(int year) {
this->publishYear = year;
}
std::string Book::getTitle() const {
return title;
}
std::string Book::getAuthor() const {
return author;
}
int Book::getPublishYear() const {
return publishYear;
}
13. 使用书籍类
最后,我们将在 main
函数中创建和使用 Book
类的实例。
// main.cpp
#include <iostream>
#include "Book.h"
int main() {
// 创建 Book 类的一个对象
Book myBook("1984", "George Orwell", 1949);
// 输出书籍信息
std::cout << "Book: " << myBook.getTitle() << std::endl;
std::cout << "Author: " << myBook.getAuthor() << std::endl;
std::cout << "Publish Year: " << myBook.getPublishYear() << std::endl;
// 修改书籍信息
myBook.setTitle("Animal Farm");
myBook.setAuthor("George Orwell");
myBook.setPublishYear(1945);
// 输出修改后的书籍信息
std::cout << "Updated Book: " << myBook.getTitle() << std::endl;
std::cout << "Updated Author: " << myBook.getAuthor() << std::endl;
std::cout << "Updated Publish Year: " << myBook.getPublishYear() << std::endl;
return 0;
}
14. 编译和运行
为了编译和运行这个程序,你可以使用类似之前的 g++
命令:
g++ Book.cpp main.cpp -o BookApp
./BookApp
Book: 1984
Author: George Orwell
Publish Year: 1949
Updated Book: Animal Farm
Updated Author: George Orwell
Updated Publish Year: 1945
这会编译你的程序并生成一个可执行文件 BookApp
,运行这个可执行文件将显示书籍信息和更新后的信息。
15. 再来一个例子
让我们设计一个更具交互性的例子,这次我们将创建一个简单的银行账户系统。这个系统会包含两个类:Account
和Bank
。Account
类将用于处理单个银行账户的基本信息和操作,如存款、取款和查询余额,而Bank
类将管理多个账户并允许添加新账户。
16. 定义账户类 Account
首先,我们定义一个Account
类,它包含账户的基本信息和操作。
// Account.h
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <string>
class Account {
public:
Account(const std::string& owner, double balance);
void deposit(double amount);
bool withdraw(double amount);
double getBalance() const;
std::string getOwner() const;
private:
std::string owner;
double balance;
};
#endif
17. 实现账户类 Account
现在,我们来实现Account
类的成员函数。
// Account.cpp
#include "Account.h"
Account::Account(const std::string& owner, double balance)
: owner(owner), balance(balance) {}
void Account::deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
bool Account::withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
double Account::getBalance() const {
return balance;
}
std::string Account::getOwner() const {
return owner;
}
18. 定义银行类 Bank
接着,我们定义一个Bank
类来管理多个Account
。
// Bank.h
#ifndef BANK_H
#define BANK_H
#include "Account.h"
#include <vector>
class Bank {
public:
void addAccount(const Account& account);
void printAccounts() const;
private:
std::vector<Account> accounts;
};
#endif
19. 实现银行类 Bank
最后,我们实现Bank
类的功能。
// Bank.cpp
#include "Bank.h"
#include <iostream>
void Bank::addAccount(const Account& account) {
accounts.push_back(account);
}
void Bank::printAccounts() const {
for (const auto& account : accounts) {
std::cout << "Owner: " << account.getOwner()
<< ", Balance: $" << account.getBalance() << std::endl;
}
}
20. 使用Account
和Bank
类
最后,我们在main
函数中使用这些类。
// main.cpp
#include "Account.h"
#include "Bank.h"
int main() {
Account a1("John Doe", 1000);
Account a2("Jane Doe", 1500);
Bank bank;
bank.addAccount(a1);
bank.addAccount(a2);
bank.printAccounts();
return 0;
}
21. 编译和运行
同样地,使用g++
将这些文件编译成一个可执行文件:
g++ Account.cpp Bank.cpp main.cpp -o BankSystem
./BankSystem
Owner: John Doe, Balance: $1000
Owner: Jane Doe, Balance: $1500
运行这个指令后,你将看到输出的账户信息,这表明我们的简易银行系统能够管理多个账户并打印它们的信息。
22. 拓展:std::string getTitle() const; 这里的std是什么意思?
在C++中,std
是标准命名空间(standard namespace)的名称,它是由C++标准库定义的。命名空间是一种将全局作用域分割的机制,用于解决命名冲突的问题,特别是当不同的库可能包含相同名称的标识符时。
在C++中,标准库中的所有组件(如 std::string
、std::vector
、std::cout
等)都被定义在 std
命名空间中。因此,当你在代码中看到 std::
前缀时,它表明你正在使用的标识符是标准库的一部分。
例如,std::string
是一个类,它提供了字符串的功能,而 std::cout
是一个对象,用于向标准输出流(通常是控制台)输出数据。
在你的代码示例中,std::string getTitle() const;
是一个成员函数声明,它返回一个 std::string
类型的值。这意味着 getTitle
函数将返回一个字符串,这个字符串是标准库中的 string
类型。const
关键字表示这个函数不会修改调用它的对象的状态,即它是一个“只读”函数。
当你在代码中使用标准库的组件时,你需要使用 std::
前缀,除非你已经通过 using
指令导入了特定的名称到当前作用域中。例如:
#include <string> // 包含string头文件
// 使用std::string,因为还没有导入到当前作用域
void someFunction() {
std::string myString = "Hello, world!";
}
// 使用using指令导入std::string到当前作用域
using std::string;
void anotherFunction() {
string anotherString = "Another message!"; // 不需要std::前缀
}
在 anotherFunction
中,由于我们已经使用 using
指令导入了 std::string
,所以可以直接使用 string
而不需要 std::
前缀。然而,在 someFunction
中,我们没有导入 std::string
,所以我们必须使用 std::string
。