一、面向对象和面向过程
在说这个定义时,我就拿c语言举例,在c语言写程序的时候,基本上就是缺什么函数,就去手搓一个函数,写的程序也只是调用函数的,而c++就是基于面向对象的开发,他关注的不再是单单的程序编写,在c语言编程过程中,我当时学习时,记得特别清楚的一句话就是,把这道题目分析一下,有几种情况,有什么极端条件,然后去根据问题写函数,在调用,就是一个面向过程的开发,而c++就是比较注重,把这个问题拆分成几块,中间有什么联系,去进行交互的,不需要关注类似于c语言的栈是怎么实现的,这个就是面向对象。
二、类的定义
C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:
之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现struct中也可以定义函数,如下方代码所示,可以看出利用c语言创造结构体的方式可以在struct里面写一个函数,这就是一个类,但是c++兼容c所以可以这样写,但是c++一般喜欢利用class来表示这个类。
#include <iostream> using namespace std; struct t { int test1() { return 1; } }; int main() { t t1; cout << t1.test1() << endl; return 0; }
如下图可以看出在我把struct换成class后编译就会报错,这是为啥?这是因为c++是面向对象的,在使用过程中肯定有一些不想让别人使用的东西,这时c++ 就提出了一个公有私有保护的概念,这里先介绍私有和公有,就是用两个英文单词中private和public一个是私人的,一个是公有的,就是在public后面就是别人可以访问的,在private后面就是不能访问的,如下方代码与图二所示可以看出,把函数放在公有区就可以正常访问了,而在这个类的里面虽然变量在后面,但是函数依然可以访问,在c++中类中函数与变量如果没定义的话,就会默认为私有。
class t { public: int test1() { return a+b; } private: int a = 1; int b = 2; }; int main() { t t1; cout << t1.test1() << endl; return 0; }
还有我们定义变量名一般都不是abcd这样,最起码都是英文单词,例如data数据,但是在进行更改变量时,如下代码该咋办,会不会很不好,这时可以更改下变量名,例如mydata,但是一般都是使用_data,我看到很多书中都是这么写的代码,上网搜了下,才知道是为了区分自己代码中变量和别的地方别冲突,这样可读性就会变高,如下方第二个代码所示
class Test { public: void Test(int data) { data = data; } private: int data; }; class Test { public: void Test(int data) { _data = data; } private: int _data; };
三、类的限定符及封装
上文已经说了类是有私有和公有的,就是类的访问限定符,访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别,这里总的说一下有五点,如下:
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)
面向对象的三大特性:封装、继承、多态。在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装本质上是一种管理,让用户更方便使用类,简单来说就是我把类的函数放在一起,封装起来,你想用哪个我提供那个给你用。
四、类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域,这里最明显的就是声明与定义分离时,是最明显的,这里如下代码所示,就是一个明显的使用,在类外面定义函数时需要加上作用域操作符,要不会访问不到的。
class Test { public: void test(); private: int _data1; int _data2; }; void Test::test() { }
五、类的实例化
用类创建对象的过程就是实例化,我想了感觉咋说都有点变扭,最后想出来,实例化就有点像我在这里存在过,这里说明这个类就是实实在在的占了内存的空间,就是和人一样存在这里,是一个实实在在存在的,这个就是实例化,就如下方代码T1就是利用Test创建了一个T1,这里就是一个实例化。
class Test { public: void test(); private: int _data1; int _data2; }; void Test::test() { } int main() { Test T1; return 0; }
六、类的对象模型
首先讲到这里肯定要计算下类的大小,这里类的计算就是只计算变量,不计算函数,这里的计算方式和c语言中的结构体计算一样就不过多解释了,对齐规则如下。
1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
类的函数时放在公共的代码段中,如果不是在代码段中,每一次创建类的时候就会非常占内存所以,这里就是放在代码段里面,然后每次都去调用。
七、tihs指针
比方说在一个类的传参中,是如何进行传参的?在c语言中是利用指针进行传参,这里只需要调用是什么原理,这时我看到了this指针,这个就是c++里面的在传参过程中,是编译器调用了一个指针,叫做this他就代表这个类,但是这指针我们可以定义吗,如下方代码可以看出这是个正常使用的并且正常打印了,结果如下图。
struct Test { public: void test(int data1, int data2) { _data1 = data1; _data2 = data2; } void print() { cout << _data1 << ' ' << _data2 << endl; } private: int _data1; int _data2; }; int main() { Test T1; T1.test(1, 2); T1.print(); return 0; }
可是他是如何知道我要打印的是T1的数据呢,这时如果把this指针带上结果是啥?报错吗?可以看出下图输出正常。
可是如果把this定义在形参里还可以正常使用吗,可以看出结果是报错了,可以看出,他是有一个隐藏的指针this支持使用,但是不能定义。
最后说一下this指针的四个特性:
1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递