面向对象编程简介
面向对象编程简介
1. 面向过程
就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调 用就可以了。C语言就是典型的面向过程。
就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调
用就可以了。C语言就是典型的面向过程。
面向过程程序设计是一种解决思路 :
-
提出问题
-
分析问题的处理流程
-
将大问题分解为小问题
-
如果小问题比较复杂,就继续划分小问题为更小的问题
-
然后通过小模块一一解决小问题
-
最后再根据整个业务流程将这些小问题串在一起(调用函数)
把大象装进冰箱需要几步?
- 打开冰箱门
- 把大象关进冰箱
- 关上冰箱门
这就是典型的面向过程的思路。为了实现这个过程我们需要写三个函数,打开冰箱函数、把大象关进冰 箱函数、关上冰箱函数。三个函数依次执行就实现了最终的效果。
- 打开冰箱函数
//打开冰箱门
返回值 openRefrigerator(参数表){//一些打开冰箱们前的操作//例如,定义变量,申请内存空间/*//计算过程//做一些其他操作//处理异常等*/std::Cout << "冰箱门打开了" << std::Endl;//做一些善后工作,例如释放空间等return 返回值;}
- 把大象关进冰箱函数
/把大象关进冰箱函数
返回值 put(参数表){//一些把大象关进冰箱的操作//例如,定义变量,申请内存空间/*//计算过程//做一些其他操作//处理异常等*/std::Cout << "大象关进冰箱了" << std::Endl;//做一些善后工作,例如释放空间等return 返回值;}
- 关上冰箱函数
//关上冰箱函数
返回值 closeRefrigerator(参数表){//一些关上冰箱的操作//例如,定义变量,申请内存空间/*//计算过程//做一些其他操作//处理异常等*/std::Cout << "冰箱关闭了" << std::Endl;//做一些善后工作,例如释放空间等return 返回值;}
调用
int main(){openRefrigerator();put();closeRefrigerator();return 0;
面向过程强调的是功能行为,以函数为最小单位,考虑怎么做。面向过程是一种以函数为基本单位的编 程方法,它将一个复杂的问题分解为多个步骤,每个步骤对应一个函数。
2 面向对象
面向对象会把事物抽象成对象的概念,先抽象出对象,然后给对象赋一些属性和方法,然后让每个对象
去执行自己的方法。
发出的; //人 ,冰箱,大象
-
定义主体(对象),为其增加属性和功能;
-
//人,人需要有打开关闭冰箱,及将大象放入冰箱的功能(行为);
-
//冰箱,冰箱需要具有能开门和关门的属性(属性);
-
//大象,大象需要具有能够进入冰箱的功能(行为)
-
将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
- 大象对象
Elephant{
类型 状态; (opening,closed)
}
- 冰箱对象
Refrigerator{返回值 enterRefrigerator(){std::cout << "进入冰箱" << std::endl;}}
- 人对象
Human{返回值 openRefrigerator(){std::cout << "打开冰箱" << std::endl;}返回值 closeRefrigerator(){std::cout << "关闭冰箱" << std::endl;}返回值 put(){std::cout << "把大象关进冰箱" << std::endl;}}
- 创建对象完成过程
int main(){// 创建大象对象Elephant;// 创建冰箱Refrigerator;// 创建人类Human;// 人打开冰箱门Human.openRefrigerator();//冰箱设置为开门状态Elephant.status = opening;// 人把大象关进冰箱Human.put();//大象进入冰箱Elephant.enterRefrigerator();// 人关闭冰箱门Human.closeRefrigerator();//冰箱设置为开门状态Elephant.status = closed;return 0;}
图示就是这样
面向对象以对象为核心,将现实世界的事物抽象为对象,每个对象拥有自己的属性和方法。面向对象编
程强调的是对象的封装、继承和多态等特性,通过这些特性实现代码的重用和扩展。在面向对象编程
中,开发者需要更多地关注对象之间的关系和交互,以及如何通过对象来描述和解决问题。
3 面向过程和面向对象的优缺点
面向过程
优点:
流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果,具体步骤清楚,便于节点分
析。
效率高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。
缺点:
耦合度高,扩展性差,后期维护难度比较大。
面向对象
优点:
结构清晰,程序是模块化和结构化,更加符合人类的思维方式;
易扩展,代码重用率高,可继承,可覆盖,可以设计出低耦合的系统;
易维护,系统低耦合的特点有利于减少程序的后期维护工作量。
缺点:
开销大,可要看到我们上述一个简单的例子需要定义三个对象,而且还要设置不同的属性和行为。另外
还要频繁设置对象属性和调用对象行为,使程序显得臃肿。
性能低,因为创建对象和销毁对象都需要损耗一定的性能。
4 面向对象的三个特征
封装
就是把细节隐藏起来,是的代码模块化,让可信的对象对访问自己的属性和方法,对不可信的进行信息
隐藏。
继承
让某个类型的对象的获得另一个类型的对象的属性和方法。通过继承创建的新类称为「子类」或「派生
类」,被继承的类称为「基类」、「父类」或「超类」。 要实现继承,可以通过 继承和组合 来实现。
继承者就是儿子,被继承着就是父亲。
多态
允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋
值给它的子对象的特性以不同的方式运作。简单说就是一句话:允许将子类类型的指针赋值给父类类型
的指针。
5 类和对象
5.1 什么是对象
万物皆对象。任何事物都可以看做对象。 三大基本特征中,最基础的特征就是封装,要理解封装,要知道两 个基本概念:类和对象。
- 类和结构体在定义时候只是一个蓝图,也是存储在指令中,实例化后才分配内存
5.2 如何描述对象
类似于结构体变量,通过对象的属性(名词,数量词,形容词…)和行为(动词)来描述对象。
描述学生对象:
属性:年龄、学号、名字
行为:吃饭、睡觉、学习
- 任何对象都属于一个类型
学生属于学生类型,不属于老师类型,更不是水果类型
- 有物体,东西的意思,现实世界中,一切都是对象(是一个具体存在的实体)
学生a、学生b...
- 任何对象都有属性和行为
属性:年龄、学号、名字
行为:吃饭、睡觉、学习
5.3 什么是类
类是将多个对象的共性提取出来定义的新的数据类型,是对对象属性和行为的抽象描述。类似于结构体类
型。
一个类型就是一个概念,类型描述了一类事物共用的特征和行为
例如:
学生类型
属性:年龄、学号、名字
行为:吃饭、睡觉、学习
零食类型
属性:产地、生产日期、保质期
行为:被人吃
class 类名
{
访问控制属性://行为:用成员函数表示返回类型 函数名(形参表){}//成员函数//属性:用成员变量表示数据类型 变量名;//成员变量
};
类就是类型,是一个抽象的概念,而对象是一个具体存在的实体,是一个类的实例的真实存在。
类(Class)和对象(Object)是面向对象编程(Object-Oriented Programming,简称OOP)中的
两个核心概念。
**类和对象的关系是抽象和实例化的关系。**类是对对象的抽象描述,而对象则是类的具体实例。
5.4 类的定义
类的一般形式
class 类名
{
访问控制属性://行为:用成员函数表示返回类型 函数名(形参表){}//成员函数//属性:用成员变量表示数据类型 变量名;//成员变量
};
访问控制属性--使用class定义的类默认的访问控制属性是private
public:公有成员,类的内部和外部都可以访问的成员
protected:表示该下面的数据成员、成员函数受保护权限,在类内可以访问,类外只有子类可以访问
private:私有成员,只有在类的内部才可以访问的成员
- 属性 :这个类的一些属性,如学生类包含:年龄、姓名、性别等,我们称为:成员变量
- 行为 :这个类的一些行为,如学生类包含:吃饭、睡觉、学习等,我们称为:成员函数
练习:描述学生对象
#include <iostream>
using namespace std;
class Student
{//成员函数 行为
public:void eat(const string food){cout << "我吃" << food << endl;}void sleep(const double hour){cout << "我睡了" << hour << "小时" << endl;}void eat(const string corse){cout << "在学" << corse << endl;}void who(){cout << "我叫" << m_name << ",年龄" << m_age << "岁,学号是" << m_no <<endl;}//成员变量 属性
public:string m_name;protected: int m_age;private:int m_no;};
5.5 类的大小
在类中,只有成员变量占用内存空间,而成员函数是不占用内存空间的
类占用的内存空间永远是所有成员中占用内存最大成员的倍数(对齐问题)。
#include <iostream>using namespace std;class student{public:void print(){cout << "hello" << endl;}private:int age; double heigh;int score;};int main(){cout << "sizeof(student) = " << sizeof(student) << endl;//24return 0;}
空类的大小为1 避免占用相同的内存
#include <iostream>using namespace std;class student{};int main(){cout << "sizeof(student) = " << sizeof(student) << endl;return 0;}
5.6 类的实例化
我们把类可以理解为一种类型,对象是类中的一种实例。用类创建对象的过程叫做实例化。与结构体变 量定义相似。
int main(){//创建对象,或实例化对象Student s1;Student s2;return 0;}
成员变量在声明时不会分配内存,而是在对象创建时分配内存
5.7 类内成员访问
与结构体变量访问结构体成员一样通过 . 来访问
protected和private成员在类外无法访问
int main(){//创建对象,或实例化对象Student s;s.eat("晚饭");s.sleep(8);s.learn("C++");s.m_name = "abc";//s.m_age = 18;//error protected成员在类外无法访问//s.m_no = 1;//error private成员在类外无法访问s.who();//随机数return 0; }
为了能使 who 函数正常使用,且不希望在外部修改成员,对程序进行修改
#include<iostream>using namespace std;class Student{public:void eat(const string food){cout << "我吃" << food << endl;}void sleep(const int hour){cout << "我睡了" << hour << "小时" << endl;}void learn(const string course){cout << "我在学" << course << endl;}void who(void){cout << "我叫" << m_name << ",今年" <<m_age << "岁,学号是" << m_no << endl;}void setAge(int age){m_age = age;}void setNo(int no){m_no = no;}public:string m_name;protected:int m_age;private:int m_no;};int main(){//创建对象,或实例化对象Student s;s.eat("晚饭");s.sleep(8);s.learn("C++");s.m_name = "abc";//s.m_age = 18;//error protected成员在类外无法访问//s.m_no = 1;//error private成员在类外无法访问s.setAge(18);s.setNo(1);s.who();return 0;}
5.8 this指针
定义:类的内部都隐藏一个该类类型的指针参数,名为this,可以帮助我们区分类内成员和其他参数。
#include<iostream>using namespace std;class Student{public:void who(void){cout << "name = " << name << endl;}void setName(string name){this->name = name;}private:string name;};int main(){Student s;s.setName("蔡徐坤");s.who();return 0;}
6.面向对象编程的注意事项
-
要确定所设计的类,那些属性和行为是对外公开的,哪些是隐藏的。默认情况下(不加访问修饰
词),class中所有的成员都是private,外界无法直接访问。
-
要符合高内聚,低耦合的设计思想
- 高内聚(High Cohesion)是指一个模块或类应该紧密地完成一个特定的功能或一组相关的功
能。高内聚意味着每个模块或类都有一个清晰定义的职责,并且模块或类内部的各个部分都是
协同工作的,以实现这个职责。这样可以提高代码的可维护性和可重用性,因为模块或类的功
能相对集中,更容易理解和修改。
- 低耦合(Low Coupling)是指模块或类之间的依赖关系应该尽可能地减少。低耦合设计可以
使模块或类更加独立,减少相互依赖和直接耦合,从而更容易进行模块替换、测试和重用。这
也有助于降低系统的复杂性,使其更容易理解和维护。
-
在定义类的时候,所有的class都可以被替换为struct,代码不会出错,但是class表示一个类,而
struct表示的是一种数据结构, class和struct最大的区别是,默认情况下(不加访问修饰
词),struct中所有的成员都是public
#include<iostream>using namespace std;class Student{std::string m_name;void print(){std::cout << "class Student" << std::endl;}};struct Teacher{std::string name;void print(){std::cout << "class Teacher" << std::endl;}};int main(){Student stu;stu.m_name = "abc";//error 默认是私有的,类外不可访问stu.print();//error默认是私有的,类外不可访问Teacher tea;tea.name = "def";tea.print();return 0;}
- 在写类的时候,一般一个标准的类都分为两个文件(.h/.cpp)
- 在头文件中声明类型和函数
test_1.h
#ifndef __TEST_1_H__#define __TEST_1_H__#include<iostream>class Student{public:void setName(const std::string name);void setAge(const int age);void who();private:std::string m_name;int m_age;};#endif
- 在源文件中实现函数
- 如果类的成员函数在类中声明,在类外定义,则在定义的时候需要加上作用域运算符
test_1.cpp
#include"test_1.h"#include<iostream>void Student::setName(const std::string name){m_name = name;}void Student::setAge(const int age){m_age = age;}void Student::who(){std::cout << "m_name = " << m_name << ", m_age = " << m_age << std::endl;}
test.cpp
#include<iostream>#include"test_1.h"using namespace std;
inline void Student::who(){std::cout << "m_name = " << m_name << ", m_age = " << m_age << std::endl;}int main(){Student s;s.setName("abc");s.setAge(18);s.who();return 0;}
- 只读成员函数(常函数)
- 在C++成员函数的形式参数列表的后面,可以加上一个const来修饰
返回值类型 函数名(参数表) const{函数体;
}
表示这个成员函数,是只读成员函数,只能读取成员变量的值,保证不修改成员变量的值 (增强程序的健壮性,防止程序员在函数中对成员变量的值进行误修改)
不允许修改成员变量
#include<iostream>class Student{void setName(std::string name) const{//m_name = name;std::cout << "m_name = " << std::endl;}private:std::string m_name;};int main(){return 0;}
-
如果在指定成员函数中,修改了成员变量的值(或者调用了非const函数), 编译器就会报错!!!
- const函数中只能调用const成员函数,在非const函数中,既可以调用const函数,又
可以调用非const函数
class Student{public:void setName1(std::string name) const{//m_name = name;std::cout << "m_name = " << m_name << std::endl;//fun1();fun2();}void setName2(std::string name){m_name = name;std::cout << "m_name = " << m_name << std::endl;fun1();fun2();}void fun1(){}void fun2() const {}private:std::string m_name;};
- const对象只能调用const成员函数,非const对象能够调用所以的成员函数
#include<iostream>class Student{public:void setName1(std::string name) const{//m_name = name;std::cout << "m_name = " << m_name << std::endl;//fun1(); error 常函数不能调用普通函数fun2();}void setName2(std::string name){m_name = name;std::cout << "m_name = " << m_name << std::endl;fun1();fun2();}void fun1(){}void fun2() const {}private:std::string m_name;};int main(){const Student stu1;stu1.setName1("abc");//不生效//stu1.setName2("abc");Student stu2;stu2.setName1("def");//不生效stu2.setName2("qwe");//生效return 0;}
- 成员函数的常版本与非常版本可构成有效重载,常对象调用常版本,非常对象调用非常版本
#include<iostream>class Student{public:void fun() const{std::cout << "常版本" << std::endl;}void fun(){std::cout << "非常版本" << std::endl;}private:std::string m_name;};int main(){Student stu1;stu1.fun();const Student stu2;stu2.fun();return 0;}