当前位置:首页>java>封装(提高代码的维护性)

封装(提高代码的维护性)

  • 2026-08-24 18:43:13
封装(提高代码的维护性)

一、封装

1. 通过类的封装,实现对外提供接口,屏蔽数据,对内开发数据,保证了代码的独立性(内聚性),提高了代码的维护性。

2. C封装 VS C++封装

  • C语言:

  • 优点:灵活,用户自定义/性能优化更方便

  • 缺点:对外提供复杂的接口,不能保证代码的独立性,无权限修饰符限制权限,容易造成内存泄漏

  • C++:

  • 优点:

i.通过访问权限,实现对外屏蔽数据,提供接口访问,对内开放数据,保证代码独立性

ii.提供更加简单的访问接口(编码器默认处理:this)

iii.防止内存泄漏:构造函数和析构函数

iv.良好可扩充性、可读性;可以自定义运算符功能

  • 缺点:占用更多内存空间,地址跳转访问(内部:更复杂的访问机制)

C++的封装本质:

将数据和行为绑定在一起,通过对象来完成操作。

重要

封装的作用?如何实现封装

  • 封装是面向对象的核心思想,解决代码独立性问题,提高代码维护性,为代码复用性和扩展性提供基础。

  • 封装将成员属性和方法绑定在一起,通过选择访问权限实现对外提供接口,对内开放数据,从而保护数据。

  • 构造和析构函数提供更安全的机制,提高开发效率。

  • 封装时,对私有属性添加 set/get 方法,全局变量会破坏数据的封装,可采用类的静态成员来解决。

对私有属性添加 set/get 方法:

  • private 关键字修饰的 m_name 和 m_age 是类的私有属性,需通过 set/get 方法操作。

  • get 方法设计:get + 属性名(首字母大写),如 getName();用于读取私有属性。

  • set 方法设计:set + 属性名(首字母大写),如 setName();用于修改私有属性。 

二、类与对象

1. 类的声明(类是一种用户自定义类型)

声明形式:

class 类名称{    public:        公有成员(外部接口)    private:        私有成员    protected:        保护成员};
  • 公有(public):类与外部的接口,任何外部函数都可以访问公有类型数据和函数。

  • 私有(private):只允许本类中的函数访问,类外部的任何函数都不能访问。

  • 保护(protected):与 private 类似,区别在于继承与派生时对派生类的影响不同。 

2. 构造函数

为什么需要构造函数?

  • 构造函数是特殊的成员函数。

  • 创建类类型的新对象时,系统会自动调用构造函数。

  • 构造函数保证对象的每个数据成员都被正确初始化,防止内存泄漏。

构造函数的定义及特点

  • 函数名和类名完全相同。

  • 不能定义构造函数的返回类型,也不能使用 void。

  • 通常应声明为公有函数,否则不能被显式调用;声明为私有有特殊用途(自动调用)。

  • 可以有任意类型和任意个数的参数,一个类可以有多个构造函数(可以重载)。

构造函数种类

1.默认构造函数(无参构造函数)

  • 无定义构造函数时,系统默认生成;自定义构造函数时,系统不会默认生成。

2.带参构造函数

  • 包含参数,可用于在创建对象时直接初始化成员变量。

构造函数初始化列表:

  • const成员、引用成员、对象成员(没有默认构造函数)只能在初始化列表中初始化。

  • C++使用初始化列表解决一些成员定义并初始化的问题,效率更高。

class Test{public:    // 使用初始化列表    Test(string n, int a, int i, int &s) : name(n), age(a), id(i), score(s)    {        cout << "初始化完成: " << endl;    }private:    string name;    int age;    int &score;    const int id;};
  • explicit:禁止发生隐式类型转换,修饰带一个参数的构造函数。

3.拷贝构造函数

  • 功能:使用一个已存在对象初始化一个新的同类型对象

  • 声明:只有一个参数并且参数为该对象的引用,如 Mystring(const Mystring &other)

  • 如果类中没有说明拷贝构造函数,系统会自动生成一个缺省复制构造函数

  • 拷贝构造函数的调用情况:

  • 用已有对象初始化对象

  • 当函数的形参是类的对象时

  • 当函数的返回值是类对象时

  • 拷贝赋值运算符:运算符重载

  • 深拷贝与浅拷贝:

  • 赋值操作(= 运算符)必须实现深拷贝

  • 禁止拷贝:可将拷贝构造函数私有化

浅拷贝 VS 深拷贝

  • 默认拷贝构造函数是浅拷贝,如果类中有指针成员,可能造成内存泄漏。

  • 解决方法: 自定义拷贝构造函数进行深拷贝,重新分配空间,使变量完全独立。

1.左值、右值、左值引用、右值引用

  • 左值特点: 指向特定内存的具有名称的值,生命周期长

  • 左引用绑定左值

  • 常引用可绑定左值和右值(但不能区分,影响拷贝效率优化)

  • 右引用绑定右值

  • -fno-elide-constructors:关闭函数返回值优化,减少拷贝构造函数的调用

  • 右引用作用: 减少堆空间拷贝,提升性能

1.移动构造函数

  • 拷贝消耗资源,尤其是临时对象、容器类

  • 对象移动:A移动到B后,A不可再用;移动是变更所有权

  • 移动拷贝构造函数、移动赋值运算符重载

  • 函数形参始终为左值

  • 左值转右值:static_cast(对象)

  • std::move:仅类型转换为右值,不实际移动对象

使用注意事项:

1.移动后源对象必须有效且可析构,指针成员需置空,防止析构时重复释放资源

2.合成的移动操作问题:定义了拷贝构造、赋值或析构,编译器不会合成移动操作

  • 定义了移动构造/赋值运算符,需同时定义拷贝构造/赋值运算符,使用 = default 显示要求编译器生成合成的移动操作

3.移动构造和移动赋值运算符必须标记为 noexcept

1.类型转换构造函数

  • 隐式转换和 explicit(禁止隐式转换,只能显示转换)

  • 类型转换运算符重载:

  • 必须为成员函数,不能为友元函数

  • 无参数

  • 不能指定返回类型(已隐式指定)原型:operator 类型名();

1.委托构造函数

  • C++11标准支持委托构造函数以减少代码冗余

  • 概念: 一个构造函数可委托同类型的另一个构造函数初始化对象

  • 执行顺序: 委托构造函数将控制权交给代理构造函数,代理构造函数执行完后再执行委托构造函数主体

  • 语法: 在委托构造函数的初始化列表中调用代理构造函数

3. 析构函数

定义:

C++类可定义一个特殊成员函数用于清理对象,称为析构函数。

语法:

~ClassName()
  • 析构函数没有参数也没有返回类型声明

  • 析构函数在对象销毁时自动被调用,不能重载

作用:

  • 释放对象成员变量所指向的内存空间,防止内存泄漏

C++类型转换运算符

  • static_cast(expr):

a)类似于C语言的强制转换,保证代码的安全性和正确性

b)可用于:相关类型转换(如整型、实型);子类转父类;void*指针与其他类型指针之间的转换

c)不可用于:指针之间类型的转换

  • const_cast(expr):

a)去除指针和引用的const属性

b)使用该运算符转换意味着代码设计存在缺陷

  • dynamic_cast(expr):

  • 运行时类型识别和检查,用于父类子类之间的转换

  • reinterpret_cast(expr):

a)编译的过程中进行类型转换

b)reinterpret重新解释:处理无关类型的转换

c)特点:不安全,既不在编译期也不在运行期进行检查,安全性完全由程序员决定

构造函数和析构函数的特点

  • 初始化一个对象的某个数据成员时,需手动初始化和手动释放,工程大的时候容易被忘记,造成内存泄漏,C++提供新的构造函数和析构函数,解决手动初始化、手动释放容易被忘记的缺点。

  • 构造函数的函数名和类名完全相同;没有返回值;可以重载

  • 析构函数的函数名和类名完全相同,没有返回值也没有参数;不可以重载

  • 构造析构函数是特殊的成员函数;创建对象时系统自动调用构造函数、在对象销毁时自动被调用

  • 构造函数是为了保证对象的每个数据成员都被正确初始化

  • 析构函数是为了保证对象的数据成员所指向的堆空间都被正确的释放

最新文章

随机文章