标签:友元 初始化 const 函数 成员 C++ 构造函数
类
C++类的定义
定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作C语言的结构体其实就是C++的类,是结构体的一种升级,但在C++下依旧可以使用结构体,因为C++兼容C 但类其实比结构体强大了不少,所以C++还是常用类
class 类名{类体:由成员函数和成员变量组成 成员变量就是内置类型:如 int float double。成员函数:就是写在类中的函数 访问限定符:public(公有权限) private(私有权限) protected(保护权限)三种访问限定符 公有权限与似有权限和保护权限的区别是: 共有权限是允许类外访问这个成员变量/成员函数 而私有权限/保护权限是不允许类外访问这个成员变量/成员函数(而私有权限和保护权限的区别这里还暂时用不到,暂不进行讲解)
访问范围说明符:
成员变量1
成员变量2
成员函数声明1
成员函数声明2
访问权限作用域从该访问限定符出现的位置直到下一个访问限定符出现时位置,如果后面没有访问限定符,作用域到 } 类结束 访问限定符只在编译时有用,当数据映射到内存时,没有任何访问限定符上的区别
当做一个项目,是需要分.h(声明) .cpp(定义) 时 我们要在声明类的函数和定义时 格式也是有稍微的改变
声明时与普通函数是相同的
定义时 在函数名前要加上对应的类域
在类里定义的函数默认时inline
短小函数可以直接在类里面定义,长一点的函数需要声明和定义分离(通常10行算做长函数)
用类类型创建对象的过程,称为对象的实例化
类的大小计算的是变量类型的内存对齐大小
类内的变量存在类中,类内的函数存在公共代码段中
当类中仅有函数或者空类,那么类的大小是1byte(字节),给它分配1byte的空间,表示他们存在过
不同对象调用同一函数,为什么会出现不同的结果?
因为编译器会做处理,把对象的地址传给函数,函数就能执行不用对象的内容。
这是自己写的
这是编译器优化的(因为这个事情是编译器干的,所以我们写出来会报错)
上面的代码说明了为什么不定义 this 就可以用
还说明了不同对象,调用相同函数,为什么出现不一样的结果。
因为:编译器优化后,传的是对线地址,用类类型指针 this 接收。但编译器优化的代码,我们不必写,写了也编译不过,还麻烦
这里是介绍一些编译器优化的地方
注意:this是 Date* const this this本身无法改变 因为被const修饰,但this指向的内容可以改变
面试题:
①结构体怎么对齐?
第一个成员在结构体偏移量为0的地址处。其他成员变量要与自身类型的整数倍地址对齐。
结构体总大小与最大类型的整数被对齐。嵌套的结构体对齐到自己最大对齐数的整数倍。结构体大小是所有对齐数的整数倍。
②为什么要进行内存对齐?
1.平台原因(移植原因)不是所有的硬件平台都能访问任意地址上的任意数据
2.性能原因:对于访问未对齐的内存,处理器需要访问两次,而对齐的内存处理只需要访问一次。
③如何指定结构体的对齐参数进行对齐?
pragram puck(指定的对齐参数)(放在结构体上一行)
④如何测试大小端
大小端就是在内存中储存字节的两种方式:
大端:高字节存放在内存的低地址处、小端:高字节储存在内存的高地址出。
int main() { int i = 0x12345678; char c = i; printf("%x \n", c); return 0;
初始化为十六进制0x12345678,在内存中存放的位置从低位到高位,依次为(低位)87654321(高位);再定义一个占一个字节的char型,然后把int型数据赋值给char型数据,因为char占一个字节,int占四个字节,这样赋值就会丢掉三个字节,但是这正是我们需要的,如果它打印出78(小端模式),如果打印出12(大端模式)。
⑤大小端的场景
1、不同端模式的处理器进行数据传递时必须要考虑端模式的不同
2、在网络上传输数据时,由于数据传输的两端对应不同的硬件平台,采用的存储字节顺序可能不一致。网络字节顺序是大端模式。对于char型数据只占一个字节,无所谓大端和小端。而对于非char类型数据,必须在数据发送到网络上之前将其转换成大端模式。接收网络数据时按符合接受主机的环境接收,我们在写网络程序的时候要注意这方面的问题。
⑥this指针存在哪里?
成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中
⑦this指针可以为空吗?
可以为空,当我们调用函数,函数内部不需要this,不用通过this指向当前对线并对其操作时,才可以为空
A、编译错误 B、运行崩溃 C、正常运行
正常运行 P指向show的地址,虽然指针时空,但P指向代码区的地址,正常调用
P->a时 P是空指针 a只是声明 并未创建空间,也是空,空指针指向空。运行错误
A、编译错误 B、运行崩溃 C、正常运行
运行崩溃 编译器优化时,把[传过去,用this指针介绍(这里P不穿地址)然后this也是空指针,而a也是空的 this->a是 空->空 运行崩溃
类的6个默认成员函数
如果一个类中什么成员都没有,简称“空类”任何一个类在什么都不写的情况下,会自动生成六个默认成员函数
1.构造函数
构造函是特殊的成员函数,需要注意的是,构造函数的名字虽然叫构造,但是构造函数主要任务并不是开空间创建对象,而是初始化对象(不传参就可以调用,都叫默认构造函数)
特征: 1.函数名与类名相同 2。无返回值 3.对象实例化时编译器自动调用对应的构造函数 4.构造函数可以重载
当我们不写构造函数,编译器默认生成一个构造函数。
内置类型/基本类型:int char double.. 自定义类型:class/struct..
默认生成构造函数对内置类型/基本类型不做处理,对自定义类型成员变量才会做处理。
一般情况 一个C++的类都要自己写构造函数,一般只有少数情况可以让编译器默认生成。
1.类里面成员都说自定义类型成员。并且这些成员都提供了默认构造函数。
2.如果还有内置类型成员,声明时给了缺省值
这两种情况可以不写构造函数,用默认构造函数
总结:如果一个类的成员全是自定义类型,用默认构造,如果有内置类型成员,或者需要传参初始化,就用自己实现的构造函数(大多数都说自己实现)
2.析构函数
析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的,而对象的销毁时会自己动调用析构函数,完成对象的一些资源清理工作
特征: 1.析构函数名实在类名前加~ 2.无参数无返回值 3.一个类有且只有一个析构函数,若未显示定义 系统会自动生成默认的析构函数(与构造相同:1.内置类型不做处理,自定义类型回去调用自定义类型(类)的析构函数)
4.对象生命周期结束时 C++编译器系统自动调用析构函数,一般用来内存释放,指针置空(局部变量由编译器销毁)
总结:若本类中有需要手动置空,释放的指针、空间就自己写,若没有,则不用写,当本类全是自定义类型,并且自定义类型成员提供了析构函数,那么就不用写,编译器回去调用自定义类型成员的析构函数
Stack s1
Stack s2
s1先构造 s2后构造
s2先析构 s1后析构
构造顺序,析构逆序 相反
3.拷贝构造
只要是同类型的对象传参,就要调用拷贝构造。
内置类型的成员会完成值拷贝,浅拷贝,自定义类型,去调用自定义类型成员的拷贝构造。
若对象中有指针,就把指针拷贝给另一个对象,这时会造成两个指针指向同一块空间。析构函数会完成两次析构,同一块空间被析构两次,就会造成运行崩溃,这个问题叫做“深浅拷贝问题”
解决方案:自己实现拷贝函数--深拷贝。
结论:一般的类,自己生成的拷贝构造就够用了。只有需要自己管理资源,需要自己实现深拷贝。
赋值运算符重载
实际上是函数
函数名 operator 运算符 (.*、::、sizeof、?:、.)五个符号不支持重载(笔试常考)
类内、类外相同重载运算符,可以同时存在,因为在不同的作用域。
有时候在类外实现,会因为限定符的限制。
三种解决方法:
一、提供公有函数,这些函数用来返回私有成员,写运算符重载是,直接使用函数。
二、使用友元
三、直接在类内实现,不存在私有权限的限制
建议成员函数中不修改成员变量的成员函数 都再后面加上const
const对象开业调用非const成员函数吗? 不可以 权限放大
非const对象可以调用const成员函数吗? 可以 权限缩小
const成员函数内可以调用其他的非const成员函数吗? 不可以 权限放大
非const成员函数内可以调用其他的const成员函数吗? 可以 权限缩小
总结:const不可以调用非const,非const可以调用const
初始化列表
以一个:(冒号)开头,已,(逗号)分割,每个成员变量后面跟一个放在括号中的初始化值或表达式
初始化列表可以认为就是对象的成员变量定义的地方,初始化列表只能初始化一次,而构造函数体内可以多次赋值。
有些变量只能再定义时初始化
不写初始化列表依旧会初始化,使用的是默认值,只会初始化一次
成员变量在类中声明次序就是其初始化中的初始化顺序,与其在初始化列表的先后次序无关
1.每个成员变量再初始化列表中只能出现一次(初始化只能初始化一次)
2.类中包括以下成员,必须再初始化列表位置进行初始化
①引用成员变量
②const成员变量
③自定义类型成员(该类没有默认构造函数)
其他的变量即可以再初始化列表初始化,也可以在函数体内初始化。
总结:建议尽量在初始化列表初始化。
Date 的=2022 这个过程可以算作隐身类型转换 用2022构造一个无名Date类型,再用这个无名Date类型拷贝给为d1
const Date& d2=2022 2022转换成Date类型,生成临时变量,被d2引用,而临时变量具有常性,所以要加const
两者的区别:
第一个是用拷贝构造,这期间没有临时变量,不需要用const 并且两次连续的拷贝,会被有优化为一个拷贝
第二个就不是拷贝构造了,而是引用,引用的是2022的临时变量,具有常性,所以要加const
在构造函数前加 explicit 修饰构造函数,禁止单构造函数的隐式转换 即禁止第一个
静态变量static
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称为静态成员变量,用static修饰的成员函数,称为静态成员函数。
静态成员变量一定要在类外进行初始化
类型 类域 静态成员变量名 = 初始值
所有对象,都可以访问静态成员。静态成员变量是存储在静态区的,不属于某个类对象
特性:
1.静态成员为所有类对象所共享,不属于某个具体的实例。
2.静态成员变量必须在类外定义,定义是不添加static关键字。
3.类静态成员即可以用类名::静态成员或者对象,静态成员来访问。
4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5.静态成员和普通成员意义,都具有三种权限限制,也具有返回值
运算符重载
cin>>的类型是istream cout>>的类型是ostream
cout<<d1
因为在类外,要访问私有权限,所以需要用到友元
cout被out引用,d1被d引用
因为要支持连续打印,输出,所以要要用cout或cin的类型作为返回类型,返回in、out的引用,支持连续打印,输出
友元
友元分为:友元函数和友元类
友元提供了一种突破封装的方式,有时提供了便利,但是友元会增加耦合性,坏了封装,所以友元不宜多用。
友元函数
友元函数可以访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以有多个类的友元函数
友元函数的调用与普通函数的调用和原理相同
友元类
友元类是所有成员函数都可以时是一个类的友元函数,都可以访问非共有成员
友元关系是单向的,不具有交换性
A声明B是友元 B可以直接访问A 但A不能访问B
总结 友元更方便,但会破坏封装,不建议多用。
内部类
一个类中再定义一个类,这个类就叫做内部类
注意:内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象取调用内部类,但内部类,可以通过外部类的对象参数访问外部类中的所有成员,但外部类不是内部类的友元
特性:
1.内部类可以定义在外部类的三种访问权限
2.内部类可以直接访问外部类的static成员,不需要外部类的对象/类名
3.sizoef(外部类)=外部类 和内部类没有关系
B天生就是A的友元 B可以访问A 但A不能访问B
若本篇文章对您有所帮助,希望能获得您的赞!
标签:友元,初始化,const,函数,成员,C++,构造函数 来源: https://www.cnblogs.com/LonelyMoNan/p/C.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。