【c++面向对象编程】第1篇:从C到C++:面向对象编程思想入门

目录

一、一个真实的故事

二、C语言的过程式思维:数据是数据,操作是操作

三、C++的面向对象思维:把数据和操作绑在一起

四、三个核心概念:用一个例子串起来

[1. 封装:把东西包起来](#1. 封装:把东西包起来)

[2. 继承:复用已有的东西](#2. 继承:复用已有的东西)

[3. 多态:同一个动作,不同表现](#3. 多态:同一个动作,不同表现)

五、一个小对比:到底好在哪里?

六、初学者最常陷入的误区

七、这一篇的收获


一、一个真实的故事

去年我刚转C++的时候,写了一个学生管理系统。

用C的思路,我定义了一个结构体,然后写了一堆函数:add_student()、find_student()、print_score()......代码跑得挺好,直到有一天,产品经理说:"每个学生需要加一个'手机号'字段。"

我改了结构体,然后满屏找哪些函数用到了学生数据------有6个文件,20多处调用。改完编译,一堆报错,折腾了一下午。

后来我用C++的类重写了一遍,同样的需求,半小时搞定。

这不是技术高低的问题,是组织代码的方式变了。


二、C语言的过程式思维:数据是数据,操作是操作

C语言编程的核心思路是:你有一堆数据,然后写一堆函数去处理它们。

c

复制代码
// C语言风格
struct Student {
    char name[20];
    int score;
};

void printStudent(struct Student* s) {
    printf("%s: %d\n", s->name, s->score);
}

int main() {
    struct Student s = {"张三", 85};
    printStudent(&s);
    return 0;
}

数据(Student结构体)和操作(printStudent函数)是分开的。代码少的时候很清晰,但项目一大,问题就来了:

  • 哪个函数改了哪个数据?很难追踪

  • 新增一个字段,所有相关函数都要检查

  • 多个模块都用同一个结构体,改一处可能炸一片

这就是过程式的痛点:数据和操作是松散的,维护成本随代码量线性增长。


三、C++的面向对象思维:把数据和操作绑在一起

面向对象告诉你:一个物体的数据和能对它做的事情,应该放在一起。

cpp

复制代码
// C++风格
class Student {
private:
    char name[20];
    int score;
public:
    void setName(const char* n) { strcpy(name, n); }
    void setScore(int s) { score = s; }
    void print() const {
        cout << name << ": " << score << endl;
    }
};

int main() {
    Student s;
    s.setName("张三");
    s.setScore(85);
    s.print();
    return 0;
}

看起来只是语法变了,但本质不一样:Student这个"类"现在是一个完整的整体,数据藏在里面,外部只能通过public函数去操作。

这就是封装------把数据和操作它的函数包在一起,把内部细节藏起来。


四、三个核心概念:用一个例子串起来

光说概念不好懂,我用一个"动物"的例子把封装、继承、多态串一遍。

1. 封装:把东西包起来

cpp

复制代码
class Animal {
private:
    int age;        // 外部不能直接访问
public:
    void setAge(int a) { 
        if (a > 0) age = a;  // 可以加校验逻辑
    }
    int getAge() const { return age; }
    void speak() { cout << "动物叫" << endl; }
};

外部的人只能通过setAge()来改年龄,不能直接animal.age = -5。封装保护了数据的一致性。

2. 继承:复用已有的东西

cpp

复制代码
class Dog : public Animal {  // Dog 继承 Animal
public:
    void wagTail() { cout << "摇尾巴" << endl; }
};

Dog自动拥有了Animal的所有成员(age、setAge、getAge、speak),还可以加自己的wagTail。不需要重新写一遍。

这就是继承的意义:站在别人的肩膀上。

3. 多态:同一个动作,不同表现

cpp

复制代码
class Cat : public Animal {
public:
    void speak() { cout << "喵喵喵" << endl; }  // 重写
};

void letItSpeak(Animal* a) {
    a->speak();  // 传Dog就汪汪,传Cat就喵喵
}

同样的speak()调用,传入不同对象,表现不一样。代码写的是一套逻辑,跑出来是多种效果。


五、一个小对比:到底好在哪里?

用C写一个"图形面积计算",你可能这样:

c

复制代码
// C:需要手动判断类型
struct Circle { float r; };
struct Rect { float w, h; };
float area(void* shape, int type) {
    if (type == 1) return ((Circle*)shape)->r * 3.14;
    if (type == 2) return ((Rect*)shape)->w * ((Rect*)shape)->h;
}
// 每加一个新形状,修改这个函数 —— 风险大

用C++写:

cpp

复制代码
class Shape {
public:
    virtual float area() = 0;  // 纯虚函数
};
class Circle : public Shape {
    float r;
public:
    float area() override { return r * r * 3.14; }
};
class Rect : public Shape {
    float w, h;
public:
    float area() override { return w * h; }
};
// 加新形状:加一个新类,已有代码完全不用改

C++的版本更安全、更容易扩展。这就是OOP对大型项目友好的原因。


六、初学者最常陷入的误区

刚学的时候我也犯过这些错,提前给你打预防针:

  1. 把所有东西都塞进一个类

    不是所有代码都需要是类。工具函数用命名空间就行,别硬塞。

  2. 滥用getter/setter,把私有变量全暴露出去

    如果每个私有变量都配一对get/set,那封装等于没做。想想"为什么外部要改它"。

  3. 以为"面向对象=用class"

    用了class不等于用了OOP思想。OOP核心是职责划分、依赖管理、可维护性,不是语法。


七、这一篇的收获

读完这篇,你应该记住三句话:

  • 封装:数据和操作放一起,内部细节藏起来

  • 继承:用已有类派生出新类,复用代码

  • 多态:同一个接口,不同对象有不同实现

下一篇我们会真正动手写第一个完整的类,从构造函数到析构函数,把对象的生命周期搞明白。

💡 一个小作业:找一个你以前用C写过的程序(比如通讯录、图书管理),想一想------如果变成类,你会怎么拆分?


下一篇预告:第2篇《类与对象(一):定义第一个类------成员变量与成员函数》,我们将真正写代码,从0构建一个可用的类。

相关推荐
无定义_2 分钟前
Codeforces Round 1124 (Div. 2)
算法
山下梅子酒2253 分钟前
洛谷-入门-B2079
c语言
(Charon)43 分钟前
【C++面试】vector底层原理:扩容、拷贝移动与迭代器失效
c++·面试
朔北之忘 Clancy1 小时前
青少年软编等考七级题解目录
开发语言·c++·青少年编程·gesp·csp·信奥赛·noi
汉克老师1 小时前
GESP2026年9月认证C++七级( 第一部分选择题(8~15题)精讲
c++·gesp·小学生·学c++编程
Mr_Macallon1 小时前
C++回顾(基础)(01)
c语言·开发语言·c++·学习
垆边人似月.2 小时前
任务混部(200 分档)
算法
言乐62 小时前
Python区分广度优先深度优先宽度优先的区别
python·算法·深度优先·广度优先·宽度优先
如意猴2 小时前
【C++】007 C/C++ 内存管理机制、malloc与new的区别及模板初阶
java·c++·算法
朝朝辞暮i2 小时前
C++ 第 32 课:main()、rclcpp::init()、spin()、shutdown()
开发语言·c++·算法