目录
一、面向过程和面向对象
什么是面向过程?
要完成一件事,关注的是过程,分析出求解问题的步骤,一步一步按照顺序完成,通过函数调用逐步解决问题。
什么是面向对象?
完成一件事,关注的是对象,将一件事情拆分成不同的对象,在对象中完成其该有的功能,靠对象之间的交互完成。
炒鸡蛋比方理解
面向过程
1.取出鸡蛋、2.敲开鸡蛋、3.将鸡蛋倒进碗里、4.筷子搅拌均匀、5.起锅、6.放油、7.点火、8.等待一定的时间后(时间不用太长,要不然把握不住),将鸡蛋倒入锅中、9.炸至金黄、10.闻到香味、11.出锅放到盘子里、12.撒点盐,开动。
按照上述过程,一步步实现,这就是面向过程。
面向对象
炒鸡蛋可分为中有哪些对象?
本人、食物(鸡蛋,盐,油)、餐具(碗、筷子、盘子,锅 )
将炒鸡蛋所需的东西,按照不同的性质分成不同的类,创建不同的对象,在对象中进行实现,最后通过对象的交互,完成炒鸡蛋。
通过各个对象间的相互交互:
本人和鸡蛋交互:完成打碎鸡蛋操作
本人和锅交互:完成起锅、出锅操作
……………
这样就可以实现各个功能,完成炒鸡蛋。
二、类的概念
类到底是个啥,咋来的呢?
听我扯一下
我们在炒鸡蛋中,食物餐具就是两个类,类包含了有相同共性的不同成员。
因此我们首先想到的是:C语言中的结构体!
c++中出现了类,要实现各个功能,就必须做到类间的交互,功能的实现我们是用函数来实现的
因此得出结论:c++中出现的类,跟我们了解到的结构体和函数有关。
引用
在c++中,是支持C语言中的结构体的;
并且对结构体做了优化,升级成了类:
1.可以在其中定义函数
2.结构体名称可以做类型
例如:
在c中定义一个结构体
在c++中定义结构体
定义
但是一般为了区分结构体和类,c++中,写类一般会将 struct 替换为 class
class className
{
// 类体:由成员函数和成员变量组成
}; // 注意后面的分号
注意
1.成员变量名,前面或后面一般会有一些区别符号:
_ 或者字母等等,目的是为了区分
2.成员变量可以定义在成员函数下方,并且常定义在下方,因为类是一个整体,不会存在找不到的问题
类就是结构体升级来的类型,而对象类这个类型定义的变量。
升级的结构体类型 = 类
结构体变量 = 对象
举例
#include <iostream>
using namespace std;
struct Food
{
//成员函数
void Init(const char* name, int num)
{
strcpy(_name, name);
_num = num;
}
void Print()
{
cout << _name << " " << _num << endl;
}
//成员变量
char _name[10];
int _num;
};
int main()
{
Food egg;
egg.Init("鸡蛋",2);
egg.Print();
return 0;
}
可以将struct 替换为class
会发现出现访问问题!!
那就是访问权限的问题!!
class不加访问限定符,默认的访问权限时私有的
struct不加访问限定符,默认的访问权限是公有的
-->访问限定符
访问限定符
public
public 修饰的成员在类外可以直接被访问
要解决上一步不可访问的问题:
加上 public:即可,如下:
private
private 修饰的成员在类外不能直接被访问
若给结构体加上private:如下:
protected
protected和private修饰的成员在类外不能直接被访问
当然是有区别的,现阶段我们只需要记住这两个效果相似就好。
封装
封装是c++面向对象的三大特性(封装、继承、多态)之一
概念
将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
c中问题
数据的定义和操作数据的方法是分开的,就比如栈。定义栈的时候,数据是在栈的定义中,而初始化,进栈,栈顶元素这些方法是在定义外实现的。
这样的布局往往会造成操作的不规范,比如想要得到栈顶元素
规范操作就直接使用我们的函数就可以,但是有不规范的人可对数据进行直接访问,往往会产生误用,如下:
c++中解决
c++如何解决上述问题?
用到封装,可以强制规范操作。
将数据和操作数据的方法放在类中,并且用访问限定符进行修饰,防止对数据的直接操作。
一般情况下,类中,数据成员都是私有的,想要被访问的函数是公有的,不想被访问的是私有或者保护。
三、类的作用域
概念
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域。
和之前学到的命名空间一样,命名空间也是一个作用域。
在类中,一般存放的是数据和函数的声明,函数在类外定义。
也可以在类中定义,要注意:
在类中定义的函数默认是内联函数,因此简短的函数可以在类中直接定义。
那么类就应在头文件中:
函数实现单独放在一个.cpp中:
函数应在类域中,函数名前应指定作用域:
这样相当于函数包括函数下面的参数都是类中直接使用的,与访问限定符没有关系。
无论是哪一个限定符修饰的成员,在类中都可以被直接调用。
四、类的实例化
概念
用类类型创建对象的过程,称为类的实例化
特征
定义出一个类并没有分配实际的内存空间来存储它
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
类相当于对象的模板
五、计算类对象的大小
类中既可以有成员变量,又可以有成员函数,如何计算一个类的大小?
存储方式猜想
对象中包含类的各个成员,函数和数据都占内存
这里,我们创建两个对象,进行相同函数成员的调用:
说明了类创建的对象函数是共用的,数据不可能共用,因为每个对象的数据都是不同的。
若按照猜想来进行存储,类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。
因此猜想错误
类的对象中只保存成员变量,成员函数存放在公共的代码段
那么类对象的大小计算就跟结构体差不多了,要注意内存对齐。
三种情况
类中既有成员变量,又有成员函数
class A1 {
public:
void f1(){}
private:
int _a;
};
只存储成员变量,按照计算结构体大小的方法,注意内存对齐
类中仅有成员函数
class A2 {
public:
void f2() {}
};
对象中不存储成员函数,但是为了保证存在这个对象,会给对象开辟一个字节的空间
类中什么都没有---空类
class A3
{};
和仅有成员一样,不存储任何东西,为了说明类创建的对象存在,会相应的给予一个字节的空间
内存对齐
链接在这:自定义类型详解_i跑跑的博客-优快云博客
六、this指针
定义一个日期类
//日期类
class Date
{
public:
void Time(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.Time(2001, 5, 15);
d2.Time(2022, 10, 30);
d1.Print();
d2.Print();
return 0;
}
this指针解决上述疑惑
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
编译器处理函数成员:
this指针特性
1. this指针的类型:类类型* const
因为是const修饰,this指针不能更改
但是被this指针修饰的内容可以更改
2. 只能在“成员函数”的内部使用
3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递指针一般存放在栈中,有些编译器优化后会存放在寄存器中,更加方便高效。
this例题
1.
class A
{
public:
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Show();
}
2.
class A
{
public:
void Show()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Show();
}
类与对象的个人理解可能存在问题,有些牵强,有问题的地方希望伙伴们私信或在讨论区帮忙指正呀,学习笔记的记录,正确是前提,希望我们都能有所收获,共同进步!!