💗 💗 博客:小怡同学
💗 💗 个人简介:编程小萌新
💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞
类
类的概念
C++是基于面向对象的,是对象与对象之间的交互完成的,类与C语言中的结构相似,是既能表示属性又能表示行为的复合数据类型,在C++中不仅可以定义变量,也可以定义函数,由这一个类型来描述一个对象。
类的定义
在C++中可以用class ,struct来定义类,class为定义类的关键字, class (?)之后是类的名字 {}之中是类的主体
类中的变量被称为成员变量或者类的属性 类中的函数被称为成员函数或者类的方法 //有两种定义方法
// 一是成员函数声明和定义全都放在类体中,编译器会默认为内联函数(但代码量很多则不会)
//二是定义与声明分离
面向对象的三大特性之封装
封装的概念
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
访问限定符
【访问限定符说明】
//public protected private
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
//当访问权限不是public时,书写方式:返回类型 类名 ::成员函数 /变量
类的实例化
//类中是声明,没有实际的储存空间,类相当于图纸,只有实例化才能由实体的储存建筑 一个类可以实例化多个对象,实例化出的对象
占用实际的物理空间,存储类成员变量
类的大小计算
对象只包含类中的各个成员 成员函数都放到公共的代码段里//因为节省内存空间 由c语言内存对齐可知类的储存大小
//没有成员变量和成员函数的类sizeof(类名)为1
this指针
- this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
- 只能在“成员函数”的内部使用
- this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。 所以对象中不存储this指针。
- this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递 //this指针作为成员函数的形参储存在栈征中,随栈征的销毁而销毁 //this指针可以为空,只不过使不使用
类的6个默认成员函数
//默认成员函数,都是创建类类型对象时由编译器自动调用,可以在类中重写各个默认成员函数
构造函数
//构造函数的任务不是开空间创建对象而是初始化对象 //创建空间实例化的时候就已经创建空间。 特征:
- 函数名与类名相同。
- 无返回值。
- 对象实例化时编译器自动调用对应的构造函数。
- 构造函数可以重载。
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成 //编译器生成的构造函数,对内置不会处理,对自定义类型会产生它的默认构造(这里指的自定义类型一般是class/struct/union)
//注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值(这里不是初始化)相当于缺省值
- 无参的构造函数和全缺省的构造函数,编译器默认构造函数都称为默认构造函数,且只有一个默认构造函数
//注意事项
析构函数
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值类型。
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重 载
- 对象生命周期结束时,C++编译系统系统自动调用析构函数。 //默认生成的析构不会对内置类型进行释放(有内存泄漏),自定义类会调用它的析构函数。例:静态数组不会释放 如int a[100]作为内置类型存储在栈上,随作用域销毁而销毁,而内置类型inta =
(int)malloc在堆上申请空间,默认编译器不会进行释放。- 编译器生成的默认析构函数,对自定类型成员调用它的析构函数.
- 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
拷贝构造函数
析构两次 ,一个拷贝会影响另一个
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错//传值拷贝,会无限形成拷贝构造,所以用引用接收一般用const Date& d
- 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝
- 注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。
- 编译器自动生成的拷贝函数就已经实现值拷贝那么重定义的意义是 当拷贝对象连申请空间都拷贝时,对象储存在栈上,当对象依次被销毁时,连拷贝的同一块空间就会析构多次,一是一个空间不能析构很多次,二是指向同一块空间,内容会一起被修改,所以需要重定义拷贝函数实现深拷贝(这里主要针对向堆申请的空间)
总结就是类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝
//自定义类型和内置类型 都不用写 默认编译器会实现stack需要自己实现- 拷贝构造函数典型调用场景: 使用已存在对象创建新对象 函数参数类型为类类型对象 函数返回值类型为类类型对象
//传值 或 值返回 可以用引用返回 减少拷贝 //不能返回局部对象的引用,栈销毁随之销毁
运算符重载
运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数 函数名字为:关键字operator后面接需要重载的运算符符号。
注意:
1.不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型参数 3用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
5…* :: sizeof ?: . 注意以上5个运算符不能重载。 // 这里需要注意的是,左操作数是this,指向调用函数的对象
赋值运算符重载
//已经存在的两个对象复制拷贝 性质:赋值运算符重载
//用一个已经存在的对象初始化另一个对象 性质:构造函数
- 赋值运算符重载格式
- 参数类型:const T&,传递引用可以提高传参效率 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值 返回*this:要复合连续赋值的含义
- 赋值运算符只能重载成类的成员函数不能重载成全局函数 //如果生成为全局,默认构造仍旧会生成一个赋值重载函数,但可以声明与定义分离(其他成员函数不能写为全局,其他符号重载可以写为全局)
- 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝
//默认生成赋值重载和拷贝构造行为一样
//1.内置类型浅拷贝
// 2.自定义类型会调用他的赋值重载,stack需要我们自己实现 //运算符重载的参数知道保证一个自定义类型
//返回类型为引用类型还是传值返回,主要看正确性,二是看效率