文章目录
?面向过程和面向对象初步认识? 类?类的引入?类的定义 ?类的访问限定符?访问限定符 ?类的两种定义方式?封装 ?总结
?面向过程和面向对象初步认识
C语言是一种面向过程的编程语言,主要关注于如何实现特定的任务或功能。在面向过程编程里**:程序是由一系列步骤或过程组成的,每个步骤都有明确的输入和输出**。数据和操作数据的函数是分开的,数据结构和算法是独立的。代码结构是线性的,更关于"how"而不是"what"。适合于一些简单的、线性的、需要快速实现的程序。
C++是一种面向对象的编程语言,它引入了类、对象、继承、多态等面向对象的概念。在面向对象编程里:关注于如何组织和封装数据和功能。程序是由相互交互的对象组成的,每个对象都有自己的数据和方法。数据和操作数据的方法是封装在类中的,形成了对象。代码结构是模块化的,更关注于"what"而不是"how"。支持继承和多态等特性,可以实现代码的重用和扩展。适合于一些复杂的、需要良好的代码组织和可维护性的程序。
我们举个例子来更透彻的理解两个过程
比如我们熟悉的PPT制作:
制作 PPT (面向过程)面向过程的做法是: 首先确定主题,然后设计版式,接下来添加内容,最后调整格式。每个步骤都是独立的。这种方式更关注于 PPT 制作过程中需要执行的具体步骤。
幻灯片演示系统 (面向对象)面向对象的做法:将 PPT 制作过程封装成一个 “幻灯片演示” 类,它包含了页面、文本、图像、动画等属性,以及添加内容、设计版式、调整格式等方法。在制作 PPT 时,我们可以创建不同的幻灯片对象,每个对象都有自己的特点和功能。这种方式更关注于幻灯片这个整体对象,以及它的属性和行为。
因此,比较可以得出:
面向过程:关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。面向对象:关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成在此,我们可以初步了解代码里C语言怎么实现面向过程的和C++语言怎么面向对象的:
我们定义了一个calculate_circle_area
函数,它接受圆的半径作为参数,计算并返回圆的面积,函数内部使用了 PI
宏定义常量,并使用公式计算面积, #include <stdio.h>#define PI 3.14159double calculate_circle_area(double radius) { return PI * radius * radius;}int main() { double radius = 5.0; double result = calculate_circle_area(radius); printf("The area of the circle with radius %.2f is %.2f\n", radius, result); return 0;}
我们定义了一个 Circle
类,它包含了圆的半径和 PI
常量作为私有属性。在构造函数 Circle(double r)
中,我们初始化了半径属性。类中还定义了一个 calculateArea
方法,用于计算圆的面积。在 main 函数中,我们创建了一个 Circle 对象,并调用它的 calculateArea
方法来获得结果。 #include <iostream>class Circle {private: double radius; const double PI = 3.14159;public: Circle(double r) : radius(r) {} double calculateArea() { return PI * radius * radius; }};int main() { Circle circle(5.0); double result = circle.calculateArea(); std::cout << "The area of the circle with radius " << circle.radius << " is " << result << std::endl; return 0;}
可以看到,C 语言的面向过程实现,是定义一个函数来计算圆的面积。而 C++ 的面向对象实现则将数据和方法封装在一个 Circle 类中,体现了面向对象的特点。
从这个例子可以看出,面向过程的实现更加直接和简单,关注于如何计算圆的面积。而面向对象的实现则将数据和方法封装在一个 Circle
类中,更加强调对象的概念和行为。
? 类
?类的引入
在 C 语言中,结构体只能包含数据成员(变量),不能包含函数。,在C++中,结构体内不仅可以定义变量,也可以定义函数。
// C 语言中的栈实现struct Stack{ int data[MAX_SIZE]; int top;};void push(struct Stack* s, int value) { // 实现 push 操作}int pop(struct Stack* s) { // 实现 pop 操作}
C语言
方式实现的栈,结构体中只能定义变量,不能包含函数。C++
升级struct
升级成了类,类里面可以定义函数,struct
名称就可以代表类型
C++兼容C中struct的用法
// C++ 中的栈实现struct Stack{ int data[MAX_SIZE]; int top; void push(int value) { // 实现 push 操作 } int pop() { // 实现 pop 操作 }};
?类的定义
class className{// 类体:由成员函数和成员变量组成}; // 一定要注意后面的分号
class
为定义类的关键字,ClassName
为类的名字,{}
中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
我们定义一个学生类:姓名,性别,年龄。
class student{int name;int sex;int age;};
在定义成员变量时,为了避免与函数参数名称混淆,通常会在成员变量前加上下划线_
作为前缀。这样可以很方便地区分成员变量和函数参数。
class Date{void Init(int year, int month, int day){_year = year;_month = month;_day = day;}int _year; int _month;int _day;};
class Date{ void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day;};int main(){Date d;d.Init(2024, 4, 8);return 0;}
在这个例子中,我们将成员变量year、month和day
分别修改为_year、_month和_day
。这样在Init()
函数中,就可以很清楚地区分函数参数和成员变量。
然后我们运行起来,会发现报了错:“Date::Init”: 无法访问 private 成员(在“Date”类中声明)
这是为什么呢?这涉及到了类的访问限定符及封装,class
默认访问限定符是private
,所以不能直接访问,为了能在类外直接访问,因此我们可以使用public访问限定符:
class Date{public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } int _year; int _month; int _day;};int main(){Date d;d.Init(2024, 4, 8);return 0;}
?类的访问限定符
?访问限定符
C++
实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
在 C++
中,访问限定符用于控制类成员的可访问性。主要有以下三种访问限定符:public
,protected
和private
。
public
:被声明为 public
的成员可以被类的任何部分以及类的外部访问。 class MyClass {public: // public 成员函数 void publicFunction() { std::cout << _publicMember << std::endl; } // public 成员变量 int _publicMember = 3;};
private
:被声明为 private
的成员只能被类的成员函数访问,类的外部无法访问。 class MyClass {protected: // protected 成员函数 void protectedFunction() { std::cout << _protectedMember << std::endl; } // protected 成员变量 int _protectedMember = 2;};
protected
:被声明为 protected
的成员可以被类的成员函数和派生类的成员函数访问,但类的外部无法访问。 class MyClass {private: // private 成员函数 void privateFunction() { std::cout << _privateMember << std::endl; } // private 成员变量 int _privateMember = 1;};
三个访问限定符结合示例:
class MyClass {public: // public 成员函数 void publicFunction() { // 可以访问 public 和 protected 成员 std::cout << _publicMember << std::endl; std::cout << _protectedMember << std::endl; // 不能访问 private 成员 // std::cout << _privateMember << std::endl; }protected: // protected 成员函数 void protectedFunction() { // 可以访问 public、protected 和 private 成员 std::cout << _publicMember << std::endl; std::cout << _protectedMember << std::endl; std::cout << _privateMember << std::endl; }private: // private 成员函数 void privateFunction() { // 可以访问 public、protected 和 private 成员 std::cout << _publicMember << std::endl; std::cout << _protectedMember << std::endl; std::cout << _privateMember << std::endl; } // private 成员变量 int _privateMember = 1; // protected 成员变量 int _protectedMember = 2; // public 成员变量 int _publicMember = 3;};
【访问限定符说明】
public
修饰的成员在类外可以直接被访问protected
和private
修饰的成员在类外不能直接被访问(此处protected
和>private
是类似的)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止如果后面没有访问限定符,作用域就到 } 即类结束。class
的默认访问权限为private
,struct
为public
(因为struct
要兼容C
)注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
【面试题】
问题:C++
中struct
和class
的区别是什么?
解答:C++
需要兼容C语言,所以C++
中struct
可以当成结构体使用。另外C++
中struct还可以用来定义类。和class
定义类是一样的,区别是struct
定义的类默认访问权限是public
,class
定义的类默认访问权限是private
。注意:在继承和模板参数列表位置,struct
和class
也有区别,后序给大家介绍。
?类的两种定义方式
声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。class Rectangle {public: Rectangle(int width, int height) : width(width), height(height) {} int getArea() { return width * height; } int getPerimeter() { return 2 * (width + height); }private: int width; int height;};
在这个例子中,Rectangle 类的构造函数和两个成员函数 getArea() 和getPerimeter() 都直接在类体中定义。
声明和定义分离:类声明放在
.h
文件中,成员函数定义放在.cpp
文件中,注意:成员函数名前需要加类名::.h
文件 class Rectangle {public: Rectangle(int width, int height); int getArea(); int getPerimeter();private: int width; int height;};
.cpp
文件
Rectangle::Rectangle(int width, int height) : width(width), height(height) {}int Rectangle::getArea() { return width * height;}int Rectangle::getPerimeter() { return 2 * (width + height);}
这里需要特别注意一下:声明和定义分离时,成员函数名前需要加类名::,这是因为编译器如果没有指定作用域时,会在全局作用域和局部作用域找。类自己定义了一个作用域,在类体外定义类成员函数时,需要用域作用域操作符::
指定哪个类域。
如果没有加指定类体域,将会出现以下报错
修改后指定类域即可修复:
?封装
面向对象的三大特性:封装、继承、多态。
封装是面向对象编程的重要思想,它通过隐藏内部实现细节,提供标准化的接口,实现了数据的安全性和系统的可维护性,是面向对象编程的基础。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
**封装本质上是一种管理,让用户更方便使用类。**比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。