C++ 类 & 对象(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在 C++ 编程的世界中,类 & 对象是面向对象编程(OOP)的核心概念,它们如同构建软件的“积木块”,让开发者能够通过抽象和封装实现高效、可维护的代码设计。无论是构建简单的控制台程序,还是开发复杂的图形界面应用,掌握 C++ 类 & 对象 的原理与实践方法,都是提升编程能力的关键一步。本文将通过循序渐进的讲解、形象的比喻和实用的代码案例,帮助读者理解这一主题。


一、类:蓝图与抽象的结合

1.1 类的定义与作用

类(Class) 是对现实世界或逻辑世界中某一类事物的抽象描述,它定义了一组属性(数据成员)和行为(成员函数)。可以将其想象为一座建筑的“设计蓝图”:蓝图中规定了房间的布局、门窗的位置(属性),以及如何建造(行为),但蓝图本身并不是实际的建筑。

例如,假设我们要描述“学生”的特征:

class Student {  
public:  
    std::string name;      // 属性:姓名  
    int age;               // 属性:年龄  
    void study() {         // 行为:学习  
        std::cout << name << " is studying." << std::endl;  
    }  
};  

在这个例子中,Student 类定义了学生的姓名、年龄以及学习行为。

1.2 成员函数与数据成员

  • 数据成员(Data Members):存储对象的状态,例如 nameage
  • 成员函数(Member Functions):定义对象的行为,例如 study() 方法。

1.3 类与结构体(struct)的区别

在 C++ 中,structclass 的语法相似,但默认访问权限不同:

  • struct 的成员默认为 public
  • class 的成员默认为 private
struct Point {  
    int x;  // public 成员  
    int y;  
};  

class Vector {  
private:  
    int x;  // private 成员  
    int y;  
};  

二、对象:类的实例化

2.1 对象的创建与初始化

对象(Object) 是类的具体实例,如同根据蓝图建造的“实际建筑”。通过 new 或直接定义变量的方式创建对象:

// 直接定义对象  
Student alice;  
alice.name = "Alice";  
alice.age = 20;  
alice.study();  // 输出:Alice is studying.  

// 动态分配内存(需手动释放)  
Student* bob = new Student();  
bob->name = "Bob";  
bob->age = 21;  
delete bob;  // 避免内存泄漏  

2.2 对象的生命周期

对象的生命周期由其作用域或内存分配方式决定。例如:

  • 局部对象在函数结束时自动销毁;
  • 动态分配的内存需通过 delete 显式释放。

三、成员函数的深入解析

3.1 普通成员函数与静态成员

  • 普通成员函数:与对象实例绑定,可以访问所有成员(包括 private)。
  • 静态成员(Static Members):属于类本身而非对象,通过 class::member 访问:
class Counter {  
public:  
    static int total;  // 静态数据成员  
    Counter() { total++; }  
};  

int Counter::total = 0;  // 静态成员需外部定义  

int main() {  
    Counter a, b;  
    std::cout << Counter::total;  // 输出:2  
}  

3.2 构造函数与析构函数

  • 构造函数(Constructor):无返回类型,与类名相同,用于初始化对象:
class Person {  
public:  
    std::string name;  
    int age;  
    Person(std::string n, int a) : name(n), age(a) {}  // 初始化列表  
};  

Person john("John", 30);  // 直接调用构造函数  
  • 析构函数(Destructor):名称前加 ~,在对象销毁时自动调用,用于释放资源:
class FileHandler {  
public:  
    ~FileHandler() {  
        std::cout << "Closing file..." << std::endl;  
    }  
};  

FileHandler fh;  // 对象销毁时自动调用析构函数  

四、访问权限与封装

4.1 访问修饰符

C++ 提供三种访问权限:
| 访问权限 | 说明 |
|----------|------|
| public | 所有代码均可访问 |
| private | 仅类内部成员函数可访问 |
| protected | 类内部和派生类可访问 |

class BankAccount {  
private:  
    double balance;  // 私有数据,外部无法直接修改  
public:  
    void deposit(double amount) {  
        balance += amount;  
    }  
};  

4.2 封装(Encapsulation)的重要性

通过将数据设为 private,并提供 public 方法操作数据(如 deposit()),可以实现数据的封装,避免外部直接篡改,从而提升代码安全性与可维护性。


五、继承:代码复用的桥梁

5.1 继承的基本语法

继承(Inheritance) 允许新类(子类)继承现有类(基类)的属性和行为,从而实现代码复用。使用 : 关键字指定继承关系:

class Vehicle {  
public:  
    void move() {  
        std::cout << "Moving..." << std::endl;  
    }  
};  

class Car : public Vehicle {  
public:  
    void accelerate() {  
        std::cout << "Accelerating..." << std::endl;  
    }  
};  

Car myCar;  
myCar.move();      // 继承自 Vehicle  
myCar.accelerate(); // 子类新增方法  

5.2 继承的类型

继承类型说明
public基类公有成员对子类为公有
protected基类公有/保护成员对子类为保护
private基类公有/保护成员对子类为私有

六、多态:行为的动态绑定

6.1 多态(Polymorphism)的实现

多态允许不同类的对象通过同一接口调用不同的实现。通过虚函数(Virtual Functions) 和基类指针/引用实现:

class Shape {  
public:  
    virtual void draw() {  
        std::cout << "Drawing shape..." << std::endl;  
    }  
};  

class Circle : public Shape {  
public:  
    void draw() override {  
        std::cout << "Drawing circle..." << std::endl;  
    }  
};  

void drawShape(Shape& s) {  
    s.draw();  
}  

int main() {  
    Circle c;  
    drawShape(c);  // 输出:Drawing circle...  
}  

6.2 虚函数与纯虚函数

  • 虚函数(Virtual Function):通过 virtual 关键字声明,允许子类重写。
  • 纯虚函数(Pure Virtual Function):强制子类实现,格式为 virtual void func() = 0,定义抽象类:
class AbstractClass {  
public:  
    virtual void pureFunc() = 0;  // 纯虚函数  
};  

七、实际案例:学生管理系统

7.1 需求分析

设计一个学生管理系统,支持:

  1. 学生信息的增删改查;
  2. 计算平均分;
  3. 继承扩展教师类。

7.2 代码实现

#include <vector>  
#include <string>  

class Person {  
protected:  
    std::string name;  
    int age;  
public:  
    Person(std::string n, int a) : name(n), age(a) {}  
    virtual void display() const {  
        std::cout << "Name: " << name << ", Age: " << age << std::endl;  
    }  
};  

class Student : public Person {  
private:  
    std::vector<double> scores;  
public:  
    Student(std::string n, int a) : Person(n, a) {}  
    void addScore(double s) { scores.push_back(s); }  
    double average() const {  
        return std::accumulate(scores.begin(), scores.end(), 0.0) / scores.size();  
    }  
    void display() const override {  
        Person::display();  
        std::cout << "Average Score: " << average() << std::endl;  
    }  
};  

class Teacher : public Person {  
public:  
    Teacher(std::string n, int a) : Person(n, a) {}  
    void teach() {  
        std::cout << name << " is teaching." << std::endl;  
    }  
};  

int main() {  
    Student alice("Alice", 20);  
    alice.addScore(90);  
    alice.addScore(85);  
    alice.display();  

    Teacher bob("Bob", 35);  
    bob.display();  
    bob.teach();  
}  

八、最佳实践与常见陷阱

8.1 常见问题与解决方案

  • 对象切片(Object Slicing):通过指针或引用传递对象,避免直接赋值:
void process(Person p) {  // 子类对象会被切片为 Person 类型  
    p.display();  
}  

// 正确做法:使用指针或引用  
void process(Person* p) {  
    p->display();  
}  
  • 避免过度继承:优先使用组合(Composition)而非继承,例如:
    class Car {  
    private:  
        Engine engine;  // 组合关系  
    };  
    

8.2 性能优化建议

  • 减少不必要的虚函数调用,因虚函数通过虚表(vtable)间接访问,可能影响性能;
  • 对于频繁创建的对象,考虑使用 std::unique_ptrstd::shared_ptr 管理内存。

结论

C++ 类 & 对象 是构建复杂程序的基石,它们通过抽象、封装、继承和多态等特性,让代码更清晰、可维护。从简单的类定义到复杂的继承体系,开发者需要逐步掌握这些工具,并通过实际项目不断实践。无论是设计游戏中的角色系统,还是构建企业级应用,理解 类 & 对象 的原理与应用,都将为你的编程之路奠定坚实的基础。

希望本文能帮助读者在 C++ 的面向对象编程之路上迈出坚实的一步!如果对某个知识点仍有疑问,欢迎在评论区留言讨论。

最新发布