文章目录
article
封装
AI文章摘要
qwen-turbo-latest
加载中...
封装概述
封装指隐藏抽象实体的实现细节, 对外提供访问和使用方式的编程思想
C语言中的分文件编写的方式、结构体也属于封装
C++的封装支持封装函数、支持权限定义,是C语言结构体的加强版.
完全解放定义能力, 使之能够拥有C语言基本数据类型的所有特性.
C++类
C语言的结构体可以封装一个事物的属性, 但不可以封装函数(方法), 方法只能在结构体外定义. C++在C语言struct的基础上添加了封装方法的特性, 更能体现面向对象的设计思想.
class person
{
权限类型:
成员;
};
类的组成
- 成员类型: 包含非静态成员和静态成员, 成员可以是变量也可以是函数.
- 非静态成员: 属于某个对象而不属于类. 非静态成员的调用必须于指定特定的对象, 对象指针- 非静态成员 或 对象.非静态成员
- 非静态成员函数: 不在对象内存中、单备份. 有个className* const this的隐藏参数, 指向调用函数的对象. 所有对非静态成员变量的修改都通过this指针
- 构造函数: 用于在对象创建时对对象进行初始化
- 析构函数: 用于对象删除时对对象的进行清理, 典型场景就是对象有指向堆内存的指针, 析构函数用于释放堆内存防止内存泄漏.
- 普通函数: 针对对象提供的函数, 若希望被常对象调用还需要对this指针添加const修饰. 格式 void test() const {……..}
- 非静态成员变量: 唯一存在于对象内存中的成员
- 非静态成员函数: 不在对象内存中、单备份. 有个className* const this的隐藏参数, 指向调用函数的对象. 所有对非静态成员变量的修改都通过this指针
- 静态成员: 属于类. 静态成员的调用可以是类也可以是对象, 它支持类似非静态成员的调用方法, 还支持类名调用 类名::静态成员. 静态成员使用static关键字修饰
- 静态成员函数: 不在对象内存中、单备份. 没有className* const this的隐藏参数, 不能修改非静态成员变量
- 静态成员变量: 不在对象内存中、单备份. 静态成员变量必须类内定义类外初始化.
- 静态内部类: 定义在类内部的类, 也叫内部类. 必须使用域运算符指明所属的类才能调用.
- 非静态成员: 属于某个对象而不属于类. 非静态成员的调用必须于指定特定的对象, 对象指针- 非静态成员 或 对象.非静态成员
- 成员权限: C++中的类成员有private, protected, public, 三种类型,
- private: 只有本类的成员可以使用, class的成员的默认权限
- protected: 供本类和继承类成员使用
- public: 所有位置都可以访问, struct的成员的默认权限
- 友元: 类的私有成员只对类成员能够访问, 如果希望非类成员也能够访问则需要在类中声明为友元
- 友元函数: 将 friend修饰的函数声明 写入类中 , 如果是类中的函数需要用作用域运算符指明所在类. 如果在类内实现的话会自动上升为全局函数.
- 友元类: 将 friend修饰的类声明 写到类中
- 注意事项: 声明友元时要确定前面已经定义, 或者声明过一次让编译器知道这东西的存在
构造函数
构造函数用来初始化一个新类对象, 它没有返回值也不能有返回值, 函数名要和类名相同 构造函数是有权限的, 只有定义在public下才能被外部调用去创建对象!!!
无参构造: 没有参数的构造函数, 有些场合必须提供无参构造.
- 定义格式:
className(){ //function define }
- 当未定义任何构造函数时, 编译器提供一个默认的无参构造, 该构造函数只进行简单的初始化操作.
- 定义格式:
有参构造: 有参数的构造函数, 具有C++的重载特性.
- 定义格式:
className(arg1,arg2,...){ //function define}
- 拷贝构造: 参数列表只有一个
cosnt className&
类型参数的构造函数, 拷贝构造就是利用提供的对象进行自身的初始化- 注意事项: 当未定义拷贝构造函数时, 编译器提供默认的拷贝构造, 该构造函数只对提供对象进行简单拷贝. 注意堆区指针的拷贝问题, 否则容易引起二次释放造成的程序崩溃
- 拷贝构造的使用场景:
- 对象创建时需要显式或隐式调用拷贝构造函数的情况, 这种情况较多.
- 对象值传入函数时, 会使用传入对象调用拷贝构造创建参数对象, 一般为了提高效率都是指针或引用传递.
- 对于以对象值作为返回值的函数, 我们清楚函数结束前会调用拷贝构造完成匿名对象的初始化, 但在release模式下通过地址变换直接在预留空间上操作, 省略了拷贝构造函数的调用来提高效率
- 转换构造: 支持自定义类型与其他类型相互转换的函数叫做转换函数. 转换函数只能在类内定义
- 其他类型转自定义类型: 其实就是单参数构造函数. 支持其他类型转换到自定义数据类型的转换, 返回匿名对象!!!
- explicit关键字: 只能用在单参数构造函数(拷贝构造除外)的用来阻止隐式类型转换. 一般的单参数构造函数都要加上. 值得注意的是, 强制类型转换仍然支持!!!!
- 注意: 拷贝构造函数虽然也是单参数构造函数, 但它不是转换函数, 同类型转换并不叫类型转换!!!!!
- 自定义类型转其他类型: operator 其他类型() const{ 定义返回的其他类型 }
- 示例: class className{ className(int para); operator int(){ rerurn 3322; } } (int)(className)2233; //2233调用了单参数构造函数生成匿名对象, 然后通过int转换函数转换成了int 3322;
- 其他类型转自定义类型: 其实就是单参数构造函数. 支持其他类型转换到自定义数据类型的转换, 返回匿名对象!!!
- 定义格式:
初始化列表: 构造函数的初始化列表可以用来初始化类成员, 调用内嵌类, 继承类的构造函数
- 语法格式: className(参数列表): 成员(参数), 内嵌类成员(构造参数), 继承类成员(构造参数), ……..{ 函数定义 }
- 初始化列表的代码优先于构造函数体代码执行, 性能也可能比函数体高.
- 初始化顺序是按照成员再类内声明的顺序执行的, 而不是参数列表顺序!!!!
- const成员, 引用成员, 没有默认构造函数的内嵌类和继承类, 是必须使用初始化列表初始化的!!!!!!
- 参数可以是参数列表的变量, 也可以是常量
析构函数
析构函数用来释放类对象占用资源的函数
- 析构函数只能有一个, 函数结束自动调用.
- 编译器默认提供了: 默认析构函数, 空操作, 并释放所以类成员 语法格式: ~className(void){析构函数操作}
- 类中有指向堆区的指针时, 默认析构会导致内存泄漏, 自定义析构解决内存释放问题
内嵌对象
- 内嵌对象指的是类中内嵌的其它类对象, 该对象的构建同样需要调用该类的构造函数.
- 内嵌对象按照类内声明顺序调用构造函数, 析构顺序恰好相反
- 内嵌对象和继承下来的基类对象有本质区别, 内嵌对象的成员不属于主类
- 主类不能调用内嵌对象的protected和private成员, 可以间接调用public成员
- 内嵌对象没有默认构造函数的需要使用参数列表法调用构造函数<详见参数列表法>
C++类对象的创建
- 创建对象的过程: 创建对象时, 编译器会先去申请对象的内存空间, 然后将对象内存空间的引用传递到指定的构造函数完成初始化工作.
- 在栈内存中创建对象:
- 普通创建方法: className target 或 className target(参数列表) 对象在函数执行结束时立即释放
- 匿名对象创建方法: className()或 className(参数列表), 匿名对象在下一条语句执行前被释放, 适用于创建一次性使用对象
- 产生匿名对象的其他场合:
- 通过函数返回产生的匿名对象: 以对象作为返回值的函数, 在返回前会调用拷贝构造函数生成一个匿名对象
- 通过类型转换产生的匿名对象: 单参数构造函数(拷贝构造除外)也是转换函数, 支持将参数类型转为自定义类型. 期间生成匿名对象 例如: (className)1
- 匿名对象的命名: className target = 匿名对象 , 命名后的匿名对象在函数执行结束时才会释放
- 产生匿名对象的其他场合:
- 在堆内存中创建对象:
- new创建: className* targetPointer = new className(参数或缺省) 对象在手动调用delete时执行析构函数释放
- 特殊对象:
- 常对象:定义时使用const修饰的对象
- 常对象只能调用常函数和静态成员函数, 以确保没有改动成员变量的操作
- 常对象只对非静态成员函数不可改(可读)
- 静态对象: 形如: static person p;
- 静态对象进入内存直接创建, 直到程序终止
- 空类对象: 空类对象内存大小是1Byte, 用于维护空类对象的地址.
- 空对象指针: 定义的对象指针设置为NULL, 若函数的访问的是非静态成员变量, 那么会宕掉. 否则这些函数都是可以运行起来的
- 常对象:定义时使用const修饰的对象