网站名称和备案公司名称不一样,做空调的网站,招聘网站数据分析怎么做,建网站 服务器文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言… 文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言和C实现Stack的对比总结 前言 哈哈类和对象可以说是我们正式学习Cpp的第一节课 上篇还不算很难甚至可以说还是蛮有意思的
正文开始 一、面向过程与面向对象初步认识
你需要很早地有个认识
C语言是面向过程的关注的是过程分析出求解问题的步骤通过函数调用逐步解决问题。C是基于面向对象的关注的是对象将一件事拆分成不同的对象靠对象之间的交互完成。 举个例子假设你点了一份外卖 面向过程 你下单——商家做饭——骑手取餐——商家骑手交接——骑手送餐——你拿到饭菜 面向对象 骑手、商家、顾客这三个 类 实例化产生的对象之间的交互 二、类的引入
在C语言中结构体中只能定义变量但在C中结构体内不仅可以定义变量还可以定义函数
struct Test
{//成员变量int a;double b;//成员函数int Add(int x, int y){return x y;}
};可是我们在C中更喜欢用 class 来代替下面来看类的定义
class className
{// 类体由成员函数和成员变量组成}; // 一定要注意后面的分号类体中内容称为类的成员其中类的成员: 类中的变量称为类的属性或成员变量类中的函数称为类的方法或成员函数 三、类的定义
声明和定义全部放在类体中 请注意成员函数如果在类中定义编译器可能会将其当成内联函数处理 声明放在头文件(.h)中定义放在源文件(.cpp)中 请注意成员函数名前需要加 “类名::” 一般情况下更期望采用第二种方式因为这样体现了面对对象编程的封装特性提高代码的可维护性 你再看上面这两段代码的成员变量你可能奇怪为什么每个变量前都有个下划线_这是为了与成员函数的形参区分开
class Date
{
// 你可能奇怪这个 public 和 private先不急哈
public:void Init(int year){// 区分一个类的成员变量和成员函数的形参通常将成员变量前或者后加一个“_”_year year;// 如若成员变量不加“_”就变成了year year; 局部变量优先导致错误}
private:int _year;
};四、类的访问限定符及类的封装
类的访问限定符 C实现封装的方式用类将对象的属性和方法结合在一块让对象更加完善通过访问权限选择性的将其接口提供给外部的用户使用 在我们还没学到继承之前你暂时先把ptotected 和 private 等同吧 public修饰的成员成员函数或者成员变量在类外可以直接被访问protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止如果后面没有访问限定符作用域就到 } 即类结束class的默认访问权限为privatestruct为public(因为struct要兼容C) 请注意访问限定符只在编译时期有效,当数据映射到内存后,没有任何访问限定符的区别 类的封装
封装将数据和操作数据的方法进行有机结合隐藏对象的属性和实现细节仅对外公开接口来和对象进行交互 绝对的自由不是自由印度火车不加以管制导致一辆车除了座位旁侧扶手甚至车顶都可以载人危险程度无可置疑地增大而封装本质上是一种高效的管理对访问权限的限制有时候是为了我们更好的使用这点大家可以有个意识慢慢再来体会 再比如计算机用户无需关心内部核心部件比如主板上线路是如何布局的CPU内部是如何设计的等用户只需要知道怎么开机、怎么通过键盘和鼠标与计算机进行交互即可 因此计算机厂商在出厂时在外部套上壳子将内部实现细节隐藏起来仅仅对外提供开关机、鼠标以及键盘插孔等让用户可以与计算机进行交互即可
五、类的作用域(类域) 类定义了一个新的作用域类的所有成员都在类的作用域中。在类体外定义成员需要使用“::”作用域解析符指明成员属于哪个类域
class Person
{
public:// 显示基本信息void ShowInfo();
private:char* _name; //姓名char* _sex; //性别int _age; //年龄
};//这里需要指定 ShowInfo 是属于 Person 这个类域
void Person::ShowInfo()
{cout _name - _sex - _age endl;
}六、类的实例化
用类创建对象的过程称为类的实例化 类本质上也是一种数据类型如intfloatdouble等只不过类是一种比较复杂的数据类型它包含多种可自助实现的功能类的成员函数既然如此那类其实并没有实际分配空间如果出现没有对类进行实例化操作而私自调用类中成员变量会报错而通过类实例化出来的对象是占用内存空间的 简单来说类就像图纸你得用它来建设房子 七、类对象模型
如何计算类对象的大小
我们先来看以下代码
#includeiostream
using namespace std;class A1 {
public:void f1(){}
private:int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};int main()
{// 4 1 1coutsizeof(A1) sizeof(A2) sizeof(A3);return 0;
}注意结构体内存对齐 可以看出来输出结果为 4、1、1这可以引发我们的一些猜测
类对象的存储方式猜测
猜测一对象中包含类的各个成员 观察到A1的输出结果为4否决其实我们分析以下道理也很显然假如每个实例化的对象的成员函数都开空间那有一百个实例化对象就开一百份空间而这些实例化的对象的属性固然不一样但函数却是一样的这造成了浪费
猜测二只保存成员变量成员函数存放在公共的代码段 这就解释了为什么A1的大小为4但是为什么A2和A3的大小不是0而是1呢 你分析一下什么是定义什么是声明定义是确确实实要开空间的尽管没有属性但我们仍要标记一下所以空类比较特殊编译器给空类一个字节来唯一标识这个类的对象表示这个对象存在过可能有成员函数
八、this指针
this指针的引出
#include iostream
using namespace std;class Date
{
public:void Display(){cout _year - _month - _day endl;}void SetDate(int year, int month, int day){_year year;_month month;_day day;}
private:int _year; // 年int _month; // 月int _day; // 日
};int main()
{Date d1, d2;//实例化两个日期类d1.SetDate(2021, 5, 25);//设置d1的日期d2.SetDate(2021, 5, 26);//设置d2的日期d1.Display();//打印d1的日期d2.Display();//打印d2的日期return 0;
}我们观察Date 类中有 Init 与 Print 两个成员函数对于函数体没有关于不同对象的区分当不同对象调用函数时该函数如何知道应该设置或打印 d1对象 而不是 d2对象 呢 C中通过引入 this 指针解决该问题即C编译器给每个非静态的成员函数增加了一个隐藏的指针参数让该指针指向当前对象(函数运行时调用该函数的对象)在函数体中所有成员变量的操作都是通过该指针去访问。只不过所有的操作对用户是透明的即用户不需要来传递编译器自动完成 编译器进行编译时看到的成员函数实际上也和我们所看到的不一样每个成员函数的第一个形参实际上是一个隐含的this指针该指针用于接收调用函数的对象的地址用this指针就可以很好地访问到该对象中的成员
this指针的特性
this指针的类型类类型* const即成员函数中不能给this赋值this指针只能在“成员函数”的内部使用。this指针本质上其实是一个成员函数的形参是对象调用成员函数时将对象地址作为实参传递给this形参所以对象中不存储this指针。this指针是成员函数第一个隐含的指针形参一般情况this指针存在栈里面因为是形参。或者由编译器通过ecx寄存器自动传递不需要用户传递。
不妨我们再通过以下代码来深入了解this指针
#include iostream
using namespace std;class A
{
public:void PrintA(){cout _a endl;}void Show(){cout Show() endl;}
private:int _a;
};int main()
{A* p nullptr; //p-Show(); // 第一句代码//p-PrintA(); // 第二句代码
}你可能看到指针p是一个空指针而第二句代码和第三句代码都通过操作符“-”间接性的执行了对p的解引用操作所以你认为程序会崩溃 其实不然当程序执行第一句代码时程序不会崩溃会正常打印出字符串Show()而当程序执行第二句代码时程序才会因为内存的非法访问而崩溃 不要陷入思维固化指针p确实是一个类的空指针但当执行第一句代码时程序并不会崩溃。第一句代码并没有对空指针p进行解引用因为Show等成员函数地址并没有存到对象里面成员函数的地址是存在公共代码段的。 当程序执行第二句代码时会因为内存的非法访问而崩溃。执行第二句代码时调用了成员函数PrintA这里并不会产生什么错误理由同上但是PrintA函数中打印了成员变量_a成员变量_a只有通过对this指针进行解引用才能访问到而this指针此时接收的是nullptr对空指针进行解引用必然会导致程序的崩溃
九、C语言和C实现Stack的对比
C语言实现栈 观察C语言实现我们会发现
每个函数的第一个参数都是Stack*函数中必须要对第一个参数检测因为该参数可能会为NULL函数中都是通过Stack*参数操作栈的调用时必须传递Stack结构体变量的地址 结构体中只能定义存放数据的结构操作数据的方法不能放在结构体中即数据和操作数据的方式是分离开的而且实现上相当复杂一点涉及到大量指针操作稍不注意可能就会出错。
Cpp实现栈 观察C实现我们会发现 C中通过类可以将** 数据 以及 操作数据的方法进行完美结合**通过访问权限可以控制那些方法在类外可以被调用即封装在使用时就像使用自己的成员一样更符合人类对一件事物的认知。而且每个方法不需要传递Stack的参数了编译器编译之后该参数会自动还原即C中 Stack 参数是编译器维护的C语言中需用用户自己维护 总结 怎么样本节内容开始有意思了起来接下来的中篇会更有意思