-
面向过程
1.1 面向过程特点
1.2 通俗解释:煮方便面
1.3 面向过程实现代码
1.4 特点总结 -
面向对象
2.1 面向对象特点
2.2 通俗解释:对象协作思维
2.3 面向对象实现代码
2.4 特点总结 -
面向对象和面向过程总结
-
C++ 面向对象介绍
4.1 面向对象三大基本特征-
封装(Encapsulation)
-
继承(Inheritance)
-
多态(Polymorphism)
4.2 三大特征的通俗解释
-
-
C++ 类与对象初识
5.1 类的定义
5.2 类的对象
5.3 类的访问控制与封装
5.4 类的成员函数-
声明与实现都放在 .h 文件中
-
声明放在 .h 文件,定义放在 .cpp 文件
-
-
总结
面向过程和面向对象
面向过程
核心是强调过程/步骤,程序就是一系列函数和语句的组合,把问题分解为一系列步骤(函数),数据在函数间传递
面向过程特点:
- 以函数为中心: 函数是主要的组织单位
- 数据与函数分离:数据结构独立存在,函数对数据进行操作
- 自顶向下设计:先规划整体流程,再逐步细化
- 适合小型程序:逻辑简单,编写快速
面向对象
强调对象,程序由对象组成,对象封装了数据(属性)和行为(方法),面向对象是通过模拟现实世界中的事物和关系来解决问题
面向对象特点:
- 以对象为中心: 对象是基本单位
- 数据与方法封装:对象内部隐藏实现细节,通过接口与外部交互
- 三大特性:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism
- 适合大型复杂系统:可扩展,可复用,可维护
通俗解释
以煮方便面为例对比面向过程和面向对象
面向过程:
思维方式: 一步步按流程来做
- 烧开水
- 打开调料包倒进碗里
- 把面饼放进开水煮熟
- 把面和汤放进碗里
- 等待一下,就可以吃了
这里每个动作就是一个"函数/步骤",整个煮面过程就是把这些步骤顺序执行
面向过程实现代码:
#include <iostream>
#include <thread>
#include <chrono> // 用于等待
using namespace std;
// 步骤 1: 烧开水
void boilWater() {cout << "正在烧开水..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "水已经烧开了。" << endl;
}
// 步骤 2: 打开调料包倒进碗里
void addSeasoning() {cout << "打开调料包,倒进碗里。" << endl;
}
// 步骤 3: 把面饼放进开水煮熟
void cookNoodles() {cout << "把面饼放进开水里煮..." << endl;this_thread::sleep_for(chrono::seconds(2));cout << "面已经煮熟了。" << endl;
}
// 步骤 4: 把面和汤放进碗里
void serveNoodles() {cout << "把面和汤一起倒进碗里。" << endl;
}
// 步骤 5: 等待一下,就可以吃了
void waitAndEat() {cout << "等待冷却一下..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "可以开动啦!" << endl;
}
int main() {boilWater();addSeasoning();cookNoodles();serveNoodles();waitAndEat();return 0;
}
特点:
- 以"过程为主"
- 如果要换成"煮饺子",要重新写一套步骤
- 不强调"面"本身的特性,只关心动作顺序
面向对象:
思维方式:把事物抽象成对象 - 有一个水壶对象,它有属性: 容量,水温,有方法: 烧水()
- 有一个面对象,它有属性:面饼大小,口味,有方法: 煮()
- 有一个调料对象,它有方法: 添加()
- 有一个人对象,他只需要调用
person.做饭(面, 水壶, 调料)
只要调用对象的方法,就能完成煮面
这里强调的是对象之间的协作,而不是具体的步骤细节
面向对象实现代码:
#include <iostream>
#include <thread>
#include <chrono>using namespace std;// 水壶对象
class Kettle {
public:void boilWater() {cout << "水壶开始烧水..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "水壶烧开了水。" << endl;}
};// 调料对象
class Seasoning {
public:void addToBowl() {cout << "调料包已倒入碗中。" << endl;}
};// 面对象
class Noodle {
public:void cook() {cout << "面饼放进开水中煮..." << endl;this_thread::sleep_for(chrono::seconds(2));cout << "面已经煮熟了。" << endl;}
};// 人对象
class Person {
public:void cookNoodles(Kettle& kettle, Seasoning& seasoning, Noodle& noodle) {kettle.boilWater(); // 调用水壶的方法seasoning.addToBowl(); // 调用调料的方法noodle.cook(); // 调用面的煮方法cout << "把面和汤一起倒进碗里。" << endl;cout << "等待冷却一下..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "可以开动啦!" << endl;}
};int main() {Kettle kettle;Seasoning seasoning;Noodle noodle;Person person;person.cookNoodles(kettle, seasoning, noodle);return 0;
}
特点:
- 以"对象"为主
- 如果换成"煮饺子",只需要定义一个饺子对象,人对象调用==做饭(饺子,水壶,调料)==就行
- 强调复用性和扩展性
面向对象和面向过程总结
面向过程是一种以步骤和函数为核心的编程思想,强调“怎么做”,适合小型、逻辑清晰的程序;而面向对象则以对象及其属性和行为为核心,强调“谁来做”,通过封装、继承和多态实现更好的复用与扩展,适合构建大型、复杂、可维护的系统
c++面向对象介绍
C++ 面向对象(OOP, Object-Oriented Programming)是一种程序设计思想,它将现实世界中的事物抽象成“对象”,通过对象之间的交互来完成程序功能。C++ 在 C 的基础上引入了类(class)和对象(object),使得它既支持面向过程(POP),又支持面向对象。
面向对象三大基本特征
C++ 面向对象的核心特性是 封装、继承、多态:
- 封装
- 把数据(成员变量)和操作数据的函数(成员函数)封装到类中,形成一个整体。
- 提供
public / private / protected
访问权限,保证数据安全。 - 举例:银行卡类,
余额
是私有的,必须通过取钱()
、存钱()
方法来访问。
- 继承
- 一个类可以继承另一个类的成员(变量和方法)。
- 允许代码复用,同时可以扩展功能
- 举例:
学生类
继承人类
,就自动拥有了姓名、年龄属性,还可以扩展为学号、成绩。
- 多态
- 相同的操作针对不同对象有不同的表现。
- 分为 静态多态(函数重载、运算符重载)和 动态多态(虚函数 + 基类指针/引用)。
- 举例:
动物
类有一个speak()
方法,狗
调用时输出“汪汪”,猫
调用时输出“喵喵”。
面向对象三大基本特征的通俗解释
封装就像一个自动售货机,你只需要按按钮投币(调用接口),不需要知道机器内部怎么找零,怎么调货(内部实现被隐藏),在编程里,封装就是把数据和操作打包起来,只暴露需要的部分。可以保护数据安全,别人不能乱动
继承就像儿子继承父亲的基因和财产,儿子天生就有父亲的特征(属性和方法,但儿子还可以有自己独特的技能(扩展功能)。在编程里,继承就是子类自动拥有父类的代码,可以复用和扩展。可以不用重复造轮子
多态就像大家就像大家都能说“打招呼”,但表达方式不同:
- 中国人说:“你好!”
- 美国人说:“Hello!”
- 日本人说:“こんにちは!”
虽然动作一样,但不同人表现不同,在编程里,多态就是同一个接口,不同对象有不同的实现。可以让代码更灵活
C++类与对象初识
- 类(class):定义了一类事物的属性和行为,是一种模板/蓝图
- 对象(object):类的实例,是实际存在的个体
类的定义
类的定义由关键字class
开始,并通过{}
包裹类的内容,类的成员包括:
- 数据成员:用于存储类对象的状态(属性)
- 成员函数:描述对象可以执行的行为(操作)
class Car {
private:string model; // 数据成员int year; // 数据成员
public:// 成员函数:用来设置车辆的型号void setModel(string m);// 成员函数:用来获取车辆的型号string getModel();// 成员函数:用来设置车辆的年份void setYear(int y);// 成员函数:用来获取车辆的年份int getYear();
};
类的对象
类定义之后,我们可以创建该类的对象,类的对象即是类的实例化
int main() {Car myCar; // 创建一个名为 myCar 的 Car 类型对象myCar.setModel("BMW"); // 设置 myCar 的 modelmyCar.setYear(2021); // 设置 myCar 的 yearcout << myCar.getModel() << " " << myCar.getYear() << endl; // 输出:BMW 2021return 0;
}
类的访问控制与封装
想象一下你在银行开了一个账户,账户里有余额,你或者其他人都不能跑到银行的数据库去修改余额,比如改成999999999999
,这样做明显是不合理的,银行只给你两个合法的窗口:存钱和取钱,这样设计的好处有:你的余额不会被随便修改,安全性高,你只需要关心“怎么存取钱”,而不用操心银行内部如何记账,银行后台可以随时升级换系统,对客户来说使用方式不变,这其实就是封装与访问控制的真实写照
为了保护数据安全,简化使用,方便维护,体现面向对象思想,C++要对类进行访问控制与封装。
在C++中,类的成员默认是私有的,也就是说,外部无法直接访问类的成员变量,如果希望外部能够访问成员,必须通过公共接口来提供访问权限
访问权限:
- public:公有成员,类外部可以访问
- private:私有成员,类外部无法直接访问
- protected:保护成员,类外部无法直接访问,但可以被派生类访问
class Car {
private:string model; // 私有成员变量
public:void setModel(string m) { model = m; } // 公有成员函数string getModel() { return model; } // 公有成员函数
};
类的成员函数
类成员函数的定义方式
在C++中,类中的成员函数可以通过两种方式进行定义:
-
将类的声明与实现都放在一个
.h
文件中 -
将类的声明放在
.h
文件中,将实现放在.cpp
文件中
我们首先来看第一种方式:
将声明和定义都放在 .h
文件中的方式
这种做法并不推荐,主要有以下几个问题:
-
可能导致重复定义:如果
.h
文件被多个源文件包含,就会在每个源文件中生成一份函数的实现,导致链接时发生重复定义错误。 -
编译速度变慢:每个源文件都会重新编译类的实现部分,导致编译时间增加。
-
模块边界不清晰:将实现放在头文件中,会让代码的结构变得不清晰,维护起来比较困难。
例如,下面是一个简单的例子:
#pragma once
#include <iostream>
#include <string>class Person {std::string _name;std::string _sex;int _age;
public:Person(std::string name, std::string sex, int age) {_name = name;_sex = sex;_age = age;}void show(); // 函数声明
};// 这里是函数定义,直接放在了头文件中
void Person::show() {std::cout << "姓名:" << _name << std::endl;std::cout << "性别:" << _sex << std::endl;std::cout << "年龄:" << _age << std::endl;
}
#include"Person.h"
int main()
{Person p("张三", "男", 20);p.show();
}
然后在另一个 .cpp
文件中:
#include"Person.h"
void test()
{Person p1("张三", "男", 20);p1.show();
}
上述代码不能成功编译,原因是头文件中的函数定义会在每个包含该头文件的 .cpp
文件中生成一份,最终会导致链接时出现重复定义的错误。
即使没有发生重复定义,编译速度也会因为每个源文件都需要重新编译函数实现部分而变慢。此外,这种做法会导致模块之间的边界不清晰,代码的结构会变得不容易维护。
将类的声明放在 .h
文件中,将实现放在 .cpp
文件中
将类的声明放在.h文件中,实现放在.cpp
文件中,是C++开发中的标准做法,不仅解决了上面重复定义的问题还带来了提升编译效率,增强代码的模块化、封装性 和 可维护性,同时也提高了 代码的可读性 和 可重用性 的好处。这种做法是C++中的标准实践
总结
在本篇博客中,我们对比了面向过程(Procedural Programming)与面向对象(Object-Oriented Programming)两种常见的编程思想,并通过通俗易懂的示例进行了讲解。
-
面向过程强调程序的执行顺序,适用于逻辑简单、功能明确的小型程序。它通过将问题拆解为一系列步骤或函数,着重于“怎么做”。
-
面向对象则通过模拟现实世界中的对象与关系,将数据与操作封装到对象中,强调“谁来做”。它通过封装、继承和多态这三大特性,提升了代码的复用性、扩展性和可维护性,适合大型、复杂的系统设计。
通过代码示例,我们展示了两种思想在实际编程中的应用。面向过程的设计直接关注操作步骤,灵活快捷,但扩展性差;而面向对象则通过抽象和封装将数据与行为结合,便于扩展与维护。不同的场景下,我们可以根据程序的复杂度和需求来选择合适的设计思想。
在学习和使用面向对象时,我们还讨论了类与对象的基本概念、封装与访问控制的实现方式,了解了如何设计和组织代码,使其更具可读性、可维护性与可扩展性。
最终,面向过程和面向对象并不是对立的,二者各有优劣。在实际开发中,我们往往会根据具体需求综合使用它们,从而达到最佳的开发效果。掌握这两种编程思想,并在合适的场景中应用,将使我们成为更高效、更有创造力的软件开发者。