C++:封装与对象特性

系列文章目录

C++内存存储模型

C++引用以及函数的占位、重载

C++封装与对象特性

C++封装与对象特性

C++对象特性及友元 

C++运算符重载及继承

C++多态

C++文件操作

C++模板



前言

封装作为C++三大特性之一,对于C++的面向对象编程有着非常重要的意义,那么封装的作用是什么呢?让我来介绍一下吧


一、封装是什么

封装(Encapsulation)是面向对象编程(OOP)的四大基本特性之一(封装、继承、多态、抽象)。它可以将类的实现细节隐藏起来,暴露出一个简洁、清晰的接口。封装提高了代码的可读性、安全性和易维护性,有利于更高效地进行软件开发。

二、封装的意义

  • 1.将属性和行为作为一个整体表现生活中的事物
  • 2.将属性和行为加以权限控制
  • 3.语法     class   类名{    访问权限:   属性/行为     }

1.意义一

比如:我们可以设计一个学生类,属性有姓名学号等

//学生类
class Student
{
public:
    //给姓名赋值
    void setName(string name)
    {
        m_name = name;
    }
    //给学号赋值
    void setID(int id)
    {
        m_id = id;
    }
    //显示学生信息
    void showStudent()
    {
        cout << "姓名:" << m_name << " 学号:" << m_id << endl;
    }
    string m_name;//姓名
    int m_id;//学号
};

int main()
{
    //创建学生对象
    Student s1;
    s1.setName("张三");
    s1.setID(1);
    s1.showStudent();
    Student s2;
    s2.setName("李四");
    s2.setID(2);
    s2.showStudent();
    return 0;
}

2.意义二

访问权限有三种

公共权限public类内可访问类外可访问
保护权限protected类内可访问类外不可以访问
私有权限private类内可访问类外不可以访问

 这其中分为类内可访问、类外可访问、类外不可以访问,那么这些访问权限都是什么意思呢?

class Person
{
public://公共权限
    string Name;
protected://保护权限
    int Age;
private://私有权限
    int Password;
public:
    void func()//
    {
        Name = "Tom";
        Age = 18;
        Password = 123456;
    }
};

int main()
{
    Person p1;
    p1.Name = "Jerry";
    //p1.Age = 18;//Age是保护权限,类外访问不到
    //p1.Password = 123456;//Password是私有权限,类外访问不到
    p1.func();//func是公共权限,类外可以访问到 
    system("pause");
    return 0;
}

代码中的Age和Password在类外都访问不到,而func()和Name在类外都能访问到 印证了上表。

3.补充

在C++中struct和class仅有一项区别

  • struct的默认权限是公共public
  • class的默认权限是私有private

三.对象特性

1.构造函数和析构函数

1.1意义

对象的初始化和清理是两个非常重要的安全问题

一个对象或者变量没有初始状态,对其使用后果是未知

同样的使用一个对象或变量,没有及时清理,也会造成一定的安全问题

C++利用了构造函数析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供。

编译器提供的构造函数和析构函数是空实现

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数有编译器自动调用,无需手动调用
  • 析构函数:主要作用在与对象销毁前系统自动调用有,执行一些清理工作
1.2构造函数用法:类名(){}

1.构造函数,没有返回值也不写void

2.函数名称与类名相同

3.构造函数可以有参数,因此可以发生重载

4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

 1.3析构函数用法:~类名(){}

1.析构函数,没有返回值也不写void

2.函数名称与类名相同,在名称前加上符合~

3.析构函数不可以有参数,因此不可以发送重载

4.程序在对象销毁前自动调用析构,无需手动调用,而且只会调用一次

1.4示例
class Person
{
public:
    Person()//构造函数可以有参数,但是不能有返回值,不能被重载
    {
        cout << "构造函数Person()调用" << endl;
    }
    ~Person()//析构函数没有参数,不能有返回值,不能被重载
    {
        cout << "析构函数~Person()调用" << endl;
    }
};

int main()
{
    Person p1;
    return 0;
}
构造函数Person()调用
析构函数~Person()调用

 代码中并未调用构造 和析构函数,但是却执行了函数内部的语句,说明构造函数和析构函数时编译器自动调用。当对象被创建时调用了构造函数,而在释放对象时调用了析构函数,如果在程序结束前加上System("pause");那么这个现象就会变得很明显。

2.构造函数的分类及调用

1.分类方式

按参数分为:有参构造和无参构造

按类型分为:普通构造和拷贝构造

2.调用方式

括号法

显示法

隐式转换法

class Person
{
public:
    Person()//构造函数可以有参数,但是不能有返回值,不能被重载
    {
        cout << "构造函数Person()调用" << endl;
    }
    Person(int a)//有参构造函数
    {
        age = a;
        cout << "有参构造函数Person(int a)调用" << endl;
    }
    Person(const Person &p)//拷贝构造函数
    {
        age = p.age;
        cout << "拷贝构造函数Person(const Person &p)调用" << endl;
    }
    ~Person()//析构函数没有参数,不能有返回值,不能被重载
    {
        cout << "析构函数~Person()调用" << endl;
    }
    int age;
};

int main()
{
    //1.括号法
    Person p1;//默认构造函数调用
    Person p2(10);//有参构造函数调用
    Person p3(p2);//拷贝构造函数调用
    //注意事项:调用默认构造函数时,不要加括号,否则会被编译器认为是函数声明
    //Person p1();这是函数声明
    //Person p1;这是调用默认构造函数
    //2.显示法
    Person p4;//默认构造函数调用
    Person p5 = Person(10);//有参构造函数调用
    Person p6 = Person(p5);//拷贝构造函数调用
    Person(10);//匿名对象 特点:当前行执行结束后,系统会立即回收掉匿名对象
    //3.隐式转换法
    Person p7 = 10;//相当于写了Person p7 = Person(10);
    Person p8 = p7;//拷贝构造函数调用
    //注意事项:不要利用拷贝构造函数初始化匿名对象 编译器会认为Person(p7) == Person p7
    //Person(p7);//编译器认为Person(p7) == Person p7
    return 0;
}

3.拷贝构造函数调用时机

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象
class Person
{
public:
    Person()//构造函数可以有参数,但是不能有返回值,不能被重载
    {
        cout << "构造函数Person()调用" << endl;
    }
    Person(int a)//有参构造函数
    {
        age = a;
        cout << "有参构造函数Person(int a)调用" << endl;
    }
    Person(const Person &p)//拷贝构造函数
    {
        age = p.age;
        cout << "拷贝构造函数Person(const Person &p)调用" << endl;
    }
    ~Person()//析构函数没有参数,不能有返回值,不能被重载
    {
        cout << "析构函数~Person()调用" << endl;
    }
    int age;
};

void doWork1(Person p)
{

}

Person doWork2()
{
    Person p1;
    return p1;
}

int main()
{
    //使用一个已经创建完毕的对象来初始化一个新对象
    Person P1(10);
    Person P2(P1);
    //值传递的方式给函数传参
    doWork1(P1);
    //值传递的方式给函数返回值
    Person P3 = doWork2();
    return 0;
}

 4.构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数,对属性进行拷贝

构造函数调用规则如下:

  • 如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,C++不会再提供其他构造函数

5.深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
    Person()
    {
        cout << "构造函数调用" << endl;
    }
    Person(int a, int height)
    {
        Height = new int(height);
        age = a;
        cout << "有参构造函数调用" << endl;
    }
    ~Person()
    {
        if (Height != NULL)
        {
            delete Height;
            Height = NULL;
        }
        cout << "析构函数调用" << endl;
    }
    int age;
    int *Height;
};

int main()
{
    Person p1(10, 180);
    Person p2(p1);
    return 0;
}

 这里我在堆区创建了变量,并且在函数析构的时候释放了,乍一看这段代码没什么问题,但是运行会发现报错了,因为拷贝构造函数让p1和p2两个对象的指针变量Height都指向了堆区的同一块内存,导致释放内存时释放了两次,而这个时候就需要深拷贝操作了。

Person(const Person &p)
    {
        age = p.age;
        Height = new int(*p.Height);
        cout << "拷贝构造函数调用" << endl;
    }

我们自己实现拷贝构造函数将两个Height指向两块不一样的地址,这样就不会重复释放了。

6.初始化列表

class Person
{
public:
    //传统初始化
    Person(int a, int b, int c)
    {
        m_A = a;
        m_B = b;
        m_C = c;
    }
    //初始化列表初始化
    Person(int a, int b, int c) : m_A(a), m_B(b), m_C(c)
    {
    }
    int m_A;
    int m_B;
    int m_C;
};

总结

本文简单介绍了C++三大特性之一的封装与部分对象特性,有些不足之处还望指出。

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值