C++的类与对象的封装

目录

1.前言以及封装的好处

2.class的结构,以及与struct的区别

1.clss的结构

2.class和struct的区别

3.class函数,即class在内存中是如何存储的

1.如果class里面没有成员变量和成员函数

2.class中有成员变量和成员函数

4.成员函数

1.自己写的成员函数:

​编辑

1.this指针

​编辑

2.默认成员函数

​编辑        

1.构造函数:

 2.析构函数

3.拷贝构造函数

 2.运算符重载

 1.普通的operator运算符重载

 2.赋值运算符重载(这个也是系统默认成员函数,你不写,系统和拷贝构造函数差不多的形似默认生成一个)

3.前置++和后置++

4.流插入,和流引出(operator<< 和operator>>)

5.const修饰成员函数


1.前言以及封装的好处

C++的类与对象是跨入面向对象编程的第一步,其中有三大特性:封装、继承、多态。

        其中,封装就是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。其实封装的本质上就是一种管理,让用户更方便使用类。

        我拿数据结构中的栈来说,下面是在C中栈的结构体,假设定义了一个对象:ST st;我们是通过push,pop等函数来实现对这个对象进行增删查改的操作,但是如果用户写出这样一句代码,你又能如何面对呢?st.a[st.top] = 1; 这是可以的吗?这明显就是用户不熟悉数据结构代码的规范性所造成的问题,所以C++祖师爷就想出了class的类,通过封装来实现它,杜绝用户写出这种让人无语的代码了。

2.class的结构,以及与struct的区别

1.clss的结构

        C++实现封装的方式:用类将对象的属性与方法结合在一起,让对象更加完美,通过访问权限选择性的将其接口提供给外部的用户使用。

C++的class分三种结构:

1.public修饰的成员在类外可以直接访问。

2.projected和private修饰的成员在类外不能直接被访问(此处的projected和private是类似的)

3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。

4.如果后面没有访问限定符,作用域就到 ‘}'

2.class和struct的区别

5.class的默认访问权限为private,struct为public(因为struct要兼容C)

3.class函数,即class在内存中是如何存储的

1.如果class里面没有成员变量和成员函数

1.那么内存大小为---1, 因为不可能为0的,那么你如果定义看class Data; 那Data d1 ,中d1变量改如果识别呢?所以肯定是要占用一个字节,来告诉编译器是有一个类存在的。

2.class中有成员变量和成员函数

1.首先,要说明的是,class的大小与成员函数有多少无关,因为成员函数是被存储在一个公共区的。假设定义了一个类class Data;变量为:Data d1;Data d2; Data d3;你想想,每一个变量都是有成员函数的,且他们其实都是一样的,d1/d2/d3不一样仅仅是private里面的成员变量而已,所以编译器就把成员函数放在一个公共区呢,要调用的时候去调用一下就OK了。

2.其次就是成员变量的存储是如何存储了,这其实是和C语言是一样的,我之前写过:http://t.csdn.cn/zeV6M

4.成员函数

1.自己写的成员函数:

下面就是一种成员函数:下面就要将细节了

1.this指针

其实在系统里,不是这样写的,而是通过this指针来实现的:

当然我们这样写肯定是不对的,因为这个形参是系统传的参数。那么this指针存在哪里呢?

1.对象里面 2.栈  3.堆  4.静态区  5.常量区         

答案是2.栈,因为this是形参,所以this指针是跟普通形参一样存在函数调用得栈桢里面的。

所以,其实也可以这样写:但是,如果你写多了,基本上是不会加this的。

下面看两个题目,相信你会更加对this有更深的理解:


2.默认成员函数


        

1.构造函数:

        我们在做项目时,很容易忘记初始化对象和有需要的销毁对象,而构造函数就是帮我们自动的初始化对象。

        是特殊的成员函数,需要注意的是,构造函数虽名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。

        特征如下:1.函数名和类名相同。2.无返回值(也不需要写void)。3.对象实例化时编译器会自动调用对应的构造函数。4.构造函数可以发生重载。5.如果类中没有显示定义构造函数,则C++
编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不再生成。

6.关于编译生成的默认成员函数,有很多同学会有疑惑:不实现构造函数的情况下,编译器会自动生成默认构造函数,但看起来默认构造函数又没什么用?但是d对象_year/_month/_day, 依旧是随机值,也就是说这里编译器生成的默认构造函数并没有什么用?

        解答:首先,要说明的是,这其实就是祖师爷的失误, 但是在C++11的标准发布会打了个布丁,但就现在其实默认构造函数也是有一席之地的。C++把类型分成内置函数(基本类型)和自定义类型,内置类型就是语言提供的数据类型,如:int、char ……, 自定义类型就是我们使用的class、struct、union等自己定义的类型,看看下面程序就会发现编译器生成默认构造函数会对自定义类型成员_t调用它的默认构造函数。

        即如果成员函数全是自定义类型,那么就不用写构造函数以及下面讲的析构函数都一样。

7.无参的构造函数和全缺省的的构造函数都被称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

 2.析构函数

        与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。而对象在销毁是会自动调用析构函数,完成对象中资源的清理工作。

        特性:1.析构函数名师在类名前加上字符‘~‘。2.无参无返回值。3.一个类只能有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。4.对象生命周期结束时,C++编译系统自动调用析构函数。

3.拷贝构造函数

        1.拷贝构造函数是构造函数的一个重载形式。

        2.拷贝构造函数的参数只有一个,且必须是类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

        3.如果没有自己开辟的内存,其实编译器默认的拷贝构造函数就足够了。因为编译的拷贝构造函数,是用内存一个一个字节直接拷贝过去的。所以开辟的空间,可能是两个变量指向同一块空间,在最后自动调用析构的话,运行会崩溃,因为第二次访问了空内存。

        首先,要解释第二点,就要了解一件事,在调用函数传参传的是自定义类型,会调用它的拷贝构造函数:(注意,这样写调试按F11就可以进入拷贝构造函数函数里面, 但是如果没有cout这行代码,就不行了,可能是编译器自己做了优化,这里作者也不是很明白。)如果我们没有定义拷贝构造函数,编译器就会调用自己系统默认的拷贝构造函数。

 所以,如果在定义拷贝构造函数时候,是传值的话,就会不断的递归,陷入死循环,但编译器会直接识别,并且报错。

 2.运算符重载

        1.C++为了增强代码的可读性引入了运算符重载,运算符重载具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型和参数列表与普通的函数类似。

        函数名字为:关键字operator后面接需要重载的运算符号。

        函数原型:返回值类型operator操作符(参数列表)

注意:

        1.不能通过连接其他符号来创建新的操作服:比如operator@

        2.重载操作符必须有一个类型参数        

        3.用于内置类型的运算符,其含义不能改变,列如:内置的整型+,不能改变其含义

        4.作为类成员函数重载是,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

        5.

 1.普通的operator运算符重载

 然后,比较运算符一起弄时,还是有点技巧的,先弄==和随便一个,下面就简单了,下面看一下:(我这个是在头文件声明了,在.c文件里面定义的,所以前面会有Data::(作用域),不理解作用域的,可以看我之间写的一篇博客,(24条消息) C++如何解决了C的命名冲突的缺陷,即namespace的详细讲解._Qianxueban的博客-CSDN博客

 2.赋值运算符重载(这个也是系统默认成员函数,你不写,系统和拷贝构造函数差不多的形似默认生成一个)

格式:(下面会解释)

        1.参数类型:const Data&,传递引用可以提高传参效率

        2.返回值类型:Data& ,返回值可以提高返回的效率,有返回值目的是为了支持连续赋值

        3.检测是否自己给自己赋值

        4.返回*this :要复合连续赋值的含义

下面有一个返回值要开辟一个临时变量,不会的可以看一下我之前写的:(24条消息) C++中的引用“&”用法_Qianxueban的博客-CSDN博客

3.前置++和后置++

(别问为什么,问就是祖师爷这么规定的,哈哈哈哈,确实当时学的时候,就是记得,后置++,就理解为*this operator++ int ----> *this++, 然后前置因为括号里没有参数了,所以变成前置了,

++*this)

4.流插入,和流引出(operator<< 和operator>>)

1.首先,我们能实现cout << int类型 等等都是因为#include <iostream>中有iostream这个自定义的类

再看下面这个,你知道为什么cout << 可以自动识别类型了吧。

1.可以直接实现内置类型是库里面实现了

2.可以直接支持自定识别类型是因为函数重载

 

 所以,新手的第一想法就是在成员函数里面定义

 

但是实现的时候就出现问题了, 是报错了的,其实你能明白为什么会报错,你就能大概理解运算符重载的本质了,这其实是什么啊?

 明白了嘛,在成员函数的运算符重载中,是默认第一个参数是this的,所以只能在类外面定义这个函数了,但是我们就不能访问私有的成员变量了,在Java中,喜欢弄一个GetYear(),GetMonth(),GetDay()的成员函数,但C++有独特的玩法就是,friend(友元函数)

 

但是又有一个问题,cout << int << int ,但我们这个肯定是不可以的,但解决这个问题,要先知道一个知识点。

 

 所以返回值应该是ostream类型,并且返回值处理函数还存在,因为iostream是在全局域中,所以可以返回引用

 cin>>也是一样实现的

 

5.const修饰成员函数

先看下面这种情况: 

它是报错的,其实想要知道为什么会报错,就看下面:(不知道权限平移,缩小,放大的看我之前写的一篇(24条消息) C++中引用“&”的权限问题_Qianxueban的博客-CSDN博客

 所以要想不报错,就要变成下面这种情况,所以祖师爷估计是左思右想(哈哈哈哈),开玩笑,祖师爷可是很厉害的,我们要保持敬畏之心,他轻轻松松地想出了这么一个办法:

所以,只要是成员函数里面,没有想着改变this的值,都可以在后面加一个const,这样也比较好些。 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值