本章类和对象将会分为三个部分。
上:类的引入,this指针
中:类的6个默认成员函数,构造函数,析构函数,拷贝构造函数,赋值运算符重载,日期类的实现
下:深入理解构造函数,static成员,友元。
类和对象上
类的引入
C语言中结构体只能定义变量,但在C++中结构体内不仅可以定义变量,还可以定义函数。
上面结构体的定义,C++一般用class代替
类的定义
class是定义类的关键字,className是类的名字,{}中是类的主体,定义类最后别忘记分号
类体中内容称为类的成员变量:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数
类的两种定义方式
1.声明和定义全部放在类体中。注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理
2.类的声明放在头文件,成员函数定义放在源文件中。注意:成员函数名前需要加类名::
一般定义类的时候都使用第二种。在定义成员变量的时候,看情况加个前缀或后缀来区分成员变量和函数形参
类的访问限定符及封装
C++实现封装的方式:用类和对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性将其接口提供给外部的用户使用
访问限定符的说明
1.public修饰的成员在类外可以直接被访问
2.protected和private修饰的成员在类外不能直接被访问。
3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4,如果后面没有访问限定符,作用域就到 } 即类结束
5.class的默认访问权限位private;struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
封装
面向对象三大特性:封装、继承、多态。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互(封装本质上是一种管理,让用户更方便使用类)
类的作用域
类定义了一个新的作用域,类的所用成员都在类的 作用域中。在类体外定义成员时,需要使用**: :**作用域操作符指明成员属于哪个类域。
类的实例化
用类的类型创建对象的过程,称为类的实例化
1.类是对对象进行描述的,定义一个类并没有分配实际内存空间来存储它。
2.一个类可以实例化出多个对象,实例化的对象占用实际的物理空间,存储类成员变量
this 指针
C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户都是透明的,即用户不需要来传递,编译器自动完成。
this指针特性
1.this指针的类型:类类型*const,即成员函数中,不能给this指针赋值
2.只能在“成员函数“的内部使用
3.this指针本质上是”成员函数“的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。
4.this指针是”成员函数“第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
类和对象中
类的6个默认成员函数
如果一个类中什么成员都没有,简称空类。
空类中,编译器会自动生成6个默认成员函数
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。(构造函数并不是开辟空间创建对象,而是初始化对象)。
构造函数特性
1.函数名与类名相同
2.无返回值
3.对象实例化时编译器自动调用对应的构造函数
4.构造函数可以重载
5.如果类中没有显示定义构造函数,则编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不再生成
6.内置类型就是语言提供的数据类型,如char int 。自定义类型就是class/struct/union等自己定义的类型。C++11中内置类型成员变量在类中声明时可以给默认值
7.无参的构造函数和全缺省构造函数都成为默认构造函数,并且默认构造函数只能有一个。包括没写构造函数,编译器自动生成的构造函数也可以认为是默认构造函数
4.注意:通过无参构造函数创建对象时,对象后面不要跟括号,否则变成函数声明
5.看类中没有构造函数的时候,编译器会自动生成无参默认构造函数;但有构造函数时,再调用无参构造函数就会报错
6.内置类型成员变量在类的声明时可以给默认值
析构函数
析构函数:与构造函数功能相反,构造函数不是完成对象本身的销毁,局部对象的销毁是由编译器完成的。对象在销毁时会自动调用析构函数,完成对象中资源的清理工作
析构函数特性:
1.析构函数名是在类名前加上字符~。
2.无参数无返回值类型
3.一个类只能有一个析构函数,若未显示定义,系统会自动生成默认的析构函数。析构函数不能重载
4.对象生命周期结束时,编译器自动调用析构函数
拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类型对象的引用(一般是const修饰),在用已存在的类类型对象创建新对象是由编译器自动调用
1.拷贝构造函数时构造函数的一个重载形式
2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,会引发无穷递归调用
3.若未显示定义,编译器会自动生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储字节序完成拷贝,这种拷贝方式叫做浅拷贝或值拷贝
4.编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝
5.拷贝构造函数典型调用场景:
(1)使用已存在对象创建新对象
(2)函数参数类型或函数返回值为类类型对象
赋值运算符重载
格式:
参数类型:const 类名& ,传递调用可以提高传参效率
返回值类型:类名& ,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否给自己赋值返回*this:要符合连续赋值的含义
类和对象下
static成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量称为静态成员变量,用static修饰成员函数称为静态成员函数。
注意
1.静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3.类静态成员即可用 类名::静态成员 或者 对象.静态成员来访问
4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5.静态成员也是类的成员,受public,protected ,private访问限定符的限制
友元
友元提供了一种突破封装的一种方式 ,提供了便利,但会增加耦合度破坏了封装,所以不宜多用
友元分为:友元函数和友元类
友元函数
1.友元函数可以直接访问类的私有和保护成员,他是定义在类外部的普通函数,不属于任何类,但在类的内部声明时需要加friend关键字
2.友元函数不能用const 修饰
3.友元函数可以在类定义的任何地方声明,不受类的访问限定符限制
4.一个函数可以是多个类的友元函数
5.友元函数和普通函数调用原理相同
友元类
1.友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类的非公有成员
2.友元关系是单向的,不具有交换性(例如:a类是b类的友元,a可以直接访问b类成员,但b不能直接访问a类成员)
3.友元关系不能传递(a是b友元,c是b友元,不能说c是a友元)
4.友元关系不能继承
内部类
一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是个独立的类,不属于外部类,也不能通过外部类的对象去访问内部类的成员。外部类没有任何优越的访问权限
注意:内部类是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但外部类不是内部类的友元
1.内部类可以定义在外部类的public, private,protect
2.内部类可以直接访问外部类中的static成员,不需要外部类的对象或类名
3.sizeof(外部类)=外部类,和内部类没有任何关系