C++类和对象
类
类构成了实现C++面向对象程序设计的基础。
类是C++封装的基本单元,它把数据和函数封装在一起。
一个类描述一类事物,描述这些事物所应具有的属性。
定义成员函数
- 类定义是提供给更多不同用途的程序共享的,并不受单个程序应用的影响而“优化”。
- 在类中定义的成员函数一般规模都比较小,且特别的switch语句不允许使用。
- 类中的函数一般为内联函数,即使没有明确用inline标明。
- 在类中定义的成员被默认为内联函数。
在类之后定义成员函数
- 将类定义和其成员函数定义分开来,是目前开发程序的通常做法。
- 我们把类定义(头文件)看成是类的外部接口,类的成员函数定义看成是类的内部实现。
- 在类定义的外部定义成员函数,需要在成员函数名前多加上一个“类名: :”
- 因为成员函数是所有对象共享的代码,不是某一个对象所独占的,所以不能在成员函数内使用某个特定的对象。
隐含的this指针
- 一般情况下,成员函数除了接受实参之外,还会接受到对象的地址。
- 这个地址被一个隐含的形参this指针所获取,等同于执行this = &x;
- 所有对数据成员的访问都隐含地被加上前缀this->。
- 所有的成员函数都会默认有this指针,static类型的函数除外。
- this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时
显示传递对象的地址给this指针。
类的访问限定符
- public(公有)
- 编制应用程序,想要使用某个类,所要了解的全部内容就是它的公共成员。
- 公共成员在任何地方都可以被访问。
- private(私有)
- 一个类定义,如果不写访问控制说明符,那么它就默认为private。
- 外部无法访问私有成员,而起到保护作用。
- protected(保护)
- 保护类的内部数据
- 保护成员对使用者来说是不可见的
- 对内部可见
- 常用于继承
- 类的访问限定符体现了面向对象的封装性。
- public(公有)
作用域
- 局部域
- 全局域
- 类域
- 名字空间域
类的作用域
类的作用域是指类定义和相应的成员函数定义范围
- 每个类都定义了自己的作用域,类的成员(成员函数/成员变量)都在类的这个作用域内,成员函数内可任意访问成员变量和其它成员函数。
- 对象可以通过 . 直接访问公有成员,指向对象的指针通过 -> 也可以直接访问对象的公有成员。
- 在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域。
对象
算法总是离不开数据结构,算法也只能适用于特定的数据结构。
在面向对象中,算法与数据结构被捆绑成一个类。
也就是说,程序就是许多对象在计算机中相继表现自己,而对象又是一个个程序实体。
一个对象是类的一个实例,它具有确定的属性。
面向对象的三大特性
- 封装
- 继承
- 多态
类和对象的区别
- 对象可以被创建和销毁,但类是无所不在的。
定义对象
- 属于不同类的对象在不同的时刻、不同的地方分别被建立。
- 全局对象在主函数开始执行前首先被建立。
- 局部对象在程序执行遇到它们的对象定义时才被建立。
- 在定义对象时,C++会为其分配空间。
对象的初始化
- C++建立和初始化对象的过程专门由该类的构造函数来完成。
- 只要对象建立,则马上会调用构造函数,给对象分配空间和初始化。
对象的内存储存模型
- 所有对象的大小为类中所有成员变量的大小之和。
- 遵循内存对齐原则——以空间换时间。
- 空类域占一个字节。
类的默认成员函数
构造函数
类的封装性,体现在一部分数据是不能让外界访问的。
所以直接在非成员函数中访问类对象的保护或私有数据是不允许的。
C++规定与类同名的成员函数是构造函数,在该类的对象创建时,自动被调用
- 构造函数没有返回类型,函数体中也不允许返回值,但可以有无值返回语句“return”。
- 构造函数不能被随意调用。
- 放在外部定义的构造函数,其函数名前需要加上“类名: :”,以区分此类成员函数和彼类成员函数。
IMPORTANT
* C++规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。
* 若未提供一个类的构造函数,则C++提供一个默认的构造函数,该默认构造函数是个无参构造函数,它仅负责创建对象,而不做任何初始化工作。
* 只要一个类定义了一个构造函数(不一定是无参构造函数),C++就不再提供默认的构造函数。也就是说,如果为类定义了一个带参数的构造函数,还想要无参构造函数,则必须自己定义。
* 与变量定义类似,在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象的位模式全为0,否则,对象值是随机的。
构造函数成员的初始化
* 方法一
d = 10;
- 方法二
SillyClass2()
:d(10)
{}
- 哪些成员变量必须放在初始化列表里面?
- 常量成员变量。(常量创建时必须初始化)
- 引用类型成员变量。(引用创建时必须初始化)
- 没有缺省构造函数的类成员变量。
拷贝构造函数
- 用一个对象去构造另一个对象,或者说,用另一个对象值初始化一个新构造的对象
- 拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
析构函数
析构函数是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载。只是在类对象生命期结束的时候,由系统自动调用。
- 作为一个类,可能有许多对象,每当对象生命期结束时,都要调用析构函数。
- 析构函数名,就是在构造函数名前加一个逻辑非运算符“~”,表示“逆构造函数”。
- 如果动态开辟了空间,需要自己重新定义一个析构函数。
赋值运算符的重载
为什么要有运算符的重载?
- 可以把C++运算符的定义扩展到运算分量是对象的情况。
- 使C++代码更直观,更易读。
5个C++不能重载的运算符:
- .*
- ::
- sizeof
- ?:
- .
- operator + 合法的运算符 构成函数名(重载<运算符的函数名:operator< )。
- 重载运算符以后,不能改变运算符的优先级/结合性/操作数个数。
- 赋值运算符的重载是对一个已存在的对象进行拷贝赋值。
- 增量运算符
- 前增量
&operator++();
- 后增量
opertor++(int);
- 前增量