一、类的地位与作用
类是面向对象程序设计方法的核心。利用类可以实现对数据的封装和隐藏,将逻辑上相关的函数与数据捆绑在一起,形成对问题的抽象描述。
在面向过程的结构化程序设计中,程序的模块由函数构成,函数将逻辑上相关的语句与数据封装起来,用于完成特定的功能。而在面向对象程序设计中,程序模块由类构成。类是对逻辑上相关的函数与数据的更高层次的封装,它描述的是一类对象的共同特征,而不仅仅是一段操作。
二、类是一种用户自定义类型
无论哪一种编程语言,其基本数据类型都是有限的。C++ 提供了 int、double、char 等基本数据类型,但它们远不能满足描述现实世界中各种对象的需要。比如现实世界中有”学生””时钟””汽车””银行账户”,这些都无法用基本数据类型直接表达。
为此,C++ 语法提供了对自定义类型的支持,这就是类。类实际上相当于一种用户自定义的类型,原则上程序员可以根据需要自定义无限多种新类型。
定义好一个类之后,就可以像使用基本类型一样使用它:
int a; // 定义基本类型变量
Student s; // 定义自定义类型(类)的对象Code language: JavaScript (javascript)
三、对象与实例化
当定义了一个类之后,便可以定义该类的变量,这个变量就称为该类的对象(或实例)。从类到对象的过程称为类的实例化。
| 概念 | 说明 | 类比 |
|---|---|---|
| 类(class) | 用户自定义的类型模板,描述一类对象的共同属性与行为 | 建筑图纸 |
| 对象(object) | 类的实例,占有实际内存空间,存储具体数据 | 按图纸建好的房子 |
| 实例化 | 从类创建对象的过程 | 按图纸施工 |
一个类可以实例化出多个对象,每个对象拥有独立的数据成员空间,但共享同一份成员函数的代码。
Student s1; // 对象1
Student s2; // 对象2
Student s3; // 对象3Code language: JavaScript (javascript)
s1、s2、s3 都是 Student 类的对象,各自有独立的姓名、年龄、成绩等数据,但调用的是同一份 display()、study() 等函数代码。
四、类的组成结构
一个典型的类由以下几部分组成:
class 类名
{
private:
数据成员声明; // 属性:描述对象的状态
public:
成员函数声明; // 行为:描述对象能执行的操作
};Code language: PHP (php)
- 数据成员:描述对象的属性特征,相当于现实事物中的”是什么”。
- 成员函数:描述对象的功能作用,相当于现实事物中的”能做什么”。
- 访问限定符:
public(对外接口)、private(内部隐藏)、protected(继承相关)。
五、代码示例
以下代码综合演示了类的定义、对象的创建与访问:
#include <iostream>
#include <string>
using namespace std;
// ===== 定义一个"银行账户"类 =====
class BankAccount
{
private:
string accountNumber; // 账号
string ownerName; // 户主姓名
double balance; // 余额
public:
// 构造函数(后面章节详细讲,此处先了解)
BankAccount()
{
balance = 0.0;
}
// 设置账户信息
void openAccount(string accNum, string owner)
{
accountNumber = accNum;
ownerName = owner;
balance = 0.0;
}
// 存款
void deposit(double amount)
{
if (amount > 0)
{
balance += amount;
cout << ownerName << " 存款 " << amount << " 元成功。" << endl;
}
else
{
cout << "存款金额无效。" << endl;
}
}
// 取款
void withdraw(double amount)
{
if (amount <= 0)
{
cout << "取款金额无效。" << endl;
}
else if (amount > balance)
{
cout << "余额不足,取款失败。" << endl;
}
else
{
balance -= amount;
cout << ownerName << " 取款 " << amount << " 元成功。" << endl;
}
}
// 查询余额
void checkBalance()
{
cout << ownerName << " 的账户 " << accountNumber
<< " 当前余额为:" << balance << " 元。" << endl;
}
// 转账
void transfer(BankAccount& target, double amount)
{
if (amount <= 0)
{
cout << "转账金额无效。" << endl;
return;
}
if (amount > balance)
{
cout << "余额不足,转账失败。" << endl;
return;
}
balance -= amount;
target.balance += amount; // 直接访问 target 的 private 成员
// 注意:同类的对象可以互相访问 private 成员
cout << ownerName << " 向 " << target.ownerName
<< " 转账 " << amount << " 元成功。" << endl;
}
};
int main()
{
// 实例化对象
BankAccount acc1;
BankAccount acc2;
// 开户
acc1.openAccount("1001", "张三");
acc2.openAccount("1002", "李四");
// 存款
acc1.deposit(1000.0);
acc2.deposit(500.0);
// 查询余额
acc1.checkBalance();
acc2.checkBalance();
cout << endl;
// 取款
acc1.withdraw(200.0);
acc1.checkBalance();
cout << endl;
// 转账
acc1.transfer(acc2, 150.0);
cout << endl;
// 再次查询余额
acc1.checkBalance();
acc2.checkBalance();
return 0;
}Code language: PHP (php)
分析:
BankAccount是一个用户自定义类型,封装了账户号、户主姓名、余额三个数据成员,以及开户、存款、取款、查询、转账等成员函数。main函数中通过BankAccount acc1;和BankAccount acc2;创建了两个对象,分别模拟两个银行账户。- 每个对象有独立的
balance,互不影响。 transfer函数中直接访问了target.balance(另一个同类型对象的私有成员),这是因为 C++ 规定:同一个类的成员函数可以访问同类其他对象的私有成员。
六、类与结构体的关系
C++ 中 struct 也可以定义类,与 class 的唯一区别是默认访问级别不同:
| 关键字 | 默认访问级别 | 典型用途 |
|---|---|---|
class | private | 面向对象设计,封装数据和行为 |
struct | public | 数据聚合(兼容 C 语言),或简单数据结构 |
struct Point // 数据聚合,成员默认 public
{
int x;
int y;
};
class Point2 // 面向对象,成员默认 private
{
private:
int x;
int y;
public:
void set(int a, int b) { x = a; y = b; }
};Code language: JavaScript (javascript)
七、注意事项
- 类定义以分号
;结尾,不可省略。 - 类是一种类型,不占用运行时内存;只有实例化出对象后才分配内存。
- 每个对象拥有独立的数据成员副本,但所有对象共享同一份成员函数代码(函数代码只有一份,存储在代码区)。
- 类体内定义的成员函数默认是
inline的;类体内声明、类体外定义的函数需要加类名::前缀。 - 类的成员函数可以访问同类任何对象的私有成员(不仅限于
this指向的那个对象)。 - 定义类时,数据成员不能初始化(C++11 起允许用
=或{}给出类内初始值,但这是初始化默认值,不是给某个对象的赋值)。
八、常见错误
1. 忘记类定义末尾的分号
class Student
{
// ...
} // 错误:缺少分号Code language: JavaScript (javascript)
2. 在类定义中直接初始化数据成员(旧标准)
class Student
{
string name = "unknown"; // C++11 之前不允许,C++11 起允许作为类内初始值
int age = 0; // 同上
};Code language: JavaScript (javascript)
注意:这是给每个对象提供的默认初始值,不是给类初始化的。
3. 类体外定义成员函数忘记加类名限定符
void checkBalance() // 错误:不知道是哪个类的成员
{
cout << balance << endl;
}Code language: JavaScript (javascript)
正确写法:
void BankAccount::checkBalance()
{
cout << balance << endl;
}Code language: JavaScript (javascript)
4. 混淆类和对象
BankAccount.balance = 100; // 错误:balance 是对象的成员,不是类的成员Code language: JavaScript (javascript)
正确写法:
BankAccount acc;
acc.deposit(100);Code language: CSS (css)