目录
常识
类
类的定义
类的两种定义方式
类的访问限定符及封装
类的作用域
类的实例化
类对象模型:
只保存成员变量,成员函数存放在公共的代码段
this指针
类的六个默认成员函数
构造函数:
初始化列表
explicit关键字:
析构函数:
拷贝构造函数:
运算符重载
赋值运算符重载:
其他
const
const成员函数
c语言中,结构体中只能定义变量,
在C++中,结构体不仅可以定义变量,也可以定义函数。
C++把类型分成内置类型(基本类型)和自定义类型。
内置类型就是语法已经定义好的类型:如 int/char...,
自定义类型就是我们使用class/struct/union自己定义的类型
class className
{
//类体:由成员函数和成员变量组成
};
class为定义类的关键字,className为类的名字,{}中为类的主体,类定义结束时后面加分号。
类中的元素称为类的成员,类中的数据称为类的属性或者成员变量,类中的函数称为类的方法或者成员函数。
1.声明和定义全部放在类体中
**成员函数如果在类中定义,编译器可能会将其当成内联函数处理。**
2.声明放在.h文件中,类的定义放在.cpp文件中。
访问限定符: public(公有) protected(保护) private(私有)
说明:
public修饰的成员在类外可以直接被访问
protected和private修饰的成员在类外不能直接被访问
*访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止。*
class的默认访问权限为private,struct为public(因为要兼容c)
注:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
类的成员都在类的作用域中。在类体外定义成员,需要使用:: (作用域解析符) 指明成员属于哪个类域。
用类类型创建对象的过程
类(相当于一个模型),限定了类中有哪些成员,定义出一个类,但没有分配实际的内存空间来存储它。
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
class Date{
private:
int _year;
int _day;
int _month;
}
int main()
{
//实例化
Date a();
Date b(2020,3,27);
Date c=b;//调用构造函数来给c赋值 c(b) 不会使用operator=
Date ();//匿名对象
}
//匿名对象只存在构造该对象的那行代码,离开构造匿名对象那行代码后立即调用析构函数。
一个类的大小,实际就是该类中成员变量之和,要进行内存对齐。
空类的大小为1个字节,因为编译器给了空类一个字节标识这个类。
C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。不需要用户来传递,编译器自动完成。
(this指针是一个隐含的指针,它指向的对象本身的,表示当前对象的地址。)
this指针的特性:只能在成员函数的内部使用
this指针的类型:类类型* const
当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,有隐含作用this指针。不用去显式的使用this指针来引用数据成员.
this指针本质上是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。*
this指针一般存放在栈,也可以放在ecx寄存器。
构造函数:主要完成初始化工作
析构函数:主要完成清理工作
拷贝构造:使用同类对象初始化创建对象
赋值重载:把一个对象赋值给另一个对象
取地址重载:主要是普通对象和const对象取地址,
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。
## 特征:
1. 函数名与类名相同。
2. 无返回值
3. 仅在对象实例时 ,编译器自动调用对应的构造函数
4. 构造函数可以重载
5. 如果类中没有显示定义构造函数,则编译器会自动生成一个无参的默认构造函数,一旦用户显式定 义编译器将不再生成。
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、编译器默认生成的构造函数,都可以认为是默认构造函数。**
编译器生成的默认构造函数对基本类型(int ,char ......)不做处理,但对于自定义类型(class,struct,union),编译器生成的默认构造函数会调用自定义类型成员的默认成员函数
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
注:**构造函数体中的语句只能将其称作为赋初值,而不能称作初始化**。
因为初始化只能初始化一次,而构造函数体内可以多次赋值。
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class Date
{
public:
Date(int year,int month,int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
}
注:
1.每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
引用成员变量
const成员变量
自定义类型成员(该类没有默认构造函数)即没有默认构造函数的自定义类型成员
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
4.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
构造函数不仅可以构造与初始化对象。对于单个参数的构造函数,还有类型转换作用
用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。
用整形给一个日期类对象赋值
编译器会用整型值(此处为2019)构造一个无名对象,最后用无名对象给a赋值
用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。
析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。(对象生命周期到了之后自动调用)
特征:
析构函数是在类名前加上字符 ~
无参数无返回值
注:
一个类有且只有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。
编译器生成的默认析构函数,对会自定义类型成员调用它的析构函数,对基本类型不做处理
只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰,)在用已存在的类类型对象创建新对象时由编译器自动调用。
## 特征:
拷贝构造函数是构造函数的一种重载形式
拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
若未显示定义,系统生成默认的拷贝构造函数。默认的拷贝构造对象按内存存储即按字节序完成拷贝,这种拷贝称为浅拷贝或值拷贝。
一般情况下,编译器自动生成的拷贝构造函数就可以完成值拷贝,但深拷贝的情况下需要自己处理。
C++为了增强程序的可读性,让自定义类型可以向内置类型一样去使用运算符,引入了运算符重载。
运算符重载是具有特殊函数名的函数。
函数原型: 返回值类型 operator 操作符( 参数列表)
注:不能通过连接其他符号来创建新的操作符,operator@
重载操作符必须有一个类类型或者枚举类型的函数。
用于内置类型的操作符,其含义不能改变。
**作为类成员的重载函数,其形参看起来比操作数目少一个成员函数(操作符中有一个默认的形参this,限定其为第一个形参)**
**注意以上5个运算符不能重载。**
返回*this
**一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝**
注:
**构造、析构等成员默认函数在语法上可以是私有的,但在实际中一般不定义成私有,因为定义为私有,就无法调用了**
定义:
将const修饰的成员函数称为const成员函数。
const修饰成员函数,实际上是修饰成员函数隐含的this指针,使该成员函数不能对类的任何成员(this指针所指向的内容)进行修改。
class Date{
public:
void Print() const
{
std::cout<<_year<<"-"<<_month<<"-"<<_day<_year<<"-"<_month<<"-"<_day<