类和对象的理解

一、类的地位与作用

类是面向对象程序设计方法的核心。利用类可以实现对数据的封装和隐藏,将逻辑上相关的函数与数据捆绑在一起,形成对问题的抽象描述。

在面向过程的结构化程序设计中,程序的模块由函数构成,函数将逻辑上相关的语句与数据封装起来,用于完成特定的功能。而在面向对象程序设计中,程序模块由类构成。类是对逻辑上相关的函数与数据的更高层次的封装,它描述的是一类对象的共同特征,而不仅仅是一段操作。

二、类是一种用户自定义类型

无论哪一种编程语言,其基本数据类型都是有限的。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 的唯一区别是默认访问级别不同:

关键字默认访问级别典型用途
classprivate面向对象设计,封装数据和行为
structpublic数据聚合(兼容 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)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注