C++基础篇:02 面向对象

1 面向过程

        关注的是如何解决问题,以及解决问题的步骤

2 面向对象

        关注的是解决问题的对象

2.1 抽象

        先找出(想象)能解决问题的“对象”,分析该对象解决问题所需要的属性(成员变量)和行为(成员函数)

2.2 封装

        把抽象的结果封装成一个类,并给类成员变量、成员函数设置相应的访问控制属性(private/protected/public)

2.3继承

        在封装类时,先考虑现有的类是否能够解决部分问题,如果有则把现有的类继承过来,在此基础上进行完善和扩展,从而缩短解决问题的时间

        把一个复杂的问题拆分成若干个不同的小问题,每个问题封装一个类去解决,最后把这些类通过继承合并成一个能解决复杂问题的类,从而降低问题规模

2.4 多态

        发出一个指令,系统会根据实际情况执行不同的相应操作,这种特征就称为多态(同一命令多种形态)

        例如重载过的函数,当调用函数时,编译器会根据参数的类型、个数,决定调用哪个重载版本,这就是编译时多态

        注意:面相对象的行为本质上还是面向过程,因此面向对象只是以更高的纬度去思考问题,而不是寻求解决问题的捷径

3 类和对象

3.1 什么是类

        类是由程序员自己设计的一种数据类型,它里面可以包含成员变量、成员函数

3.2 什么是对象

        对象是类的实例化,可以理解成使用类来创建的变量

① 类的设计和实例化

class 类名
{
    成员变量; //类中默认属性是private
public:
    成员函数;
};

② 实例化

        方法1:类名 类对象;

        方法2:类名* p = new 类名;

③ 类的声明、实现和调用

一般在头文件中声明:

 class 类名
{
    成员变量;   //  类中的默认属性是private私有的
public:
    返回值 成员函数(参数列表);
};

一般在源文件中实现成员函数:

返回值 类名::成员函数(参数列表)
{
    //  在成员函数中可以直接使用成员变量,无需. ->
}

注意:如果类的成员函数内容不多,可以考虑直接在头文件中实现

④ 类中的访问控制属性

public公开的,被它修饰的成员变量、成员函数可以在类外任意位置访问,一般会把成员函数设置为public
private私有的,被它修饰的成员变量、成员函数只能在类内访问,类的默认访问控制属性是private,一般为了确保属性的封装性会把成员变量设置为private
protected保护的,被它修饰的成员变量、成员函数只能在类内和其子类中访问,但是不能在类外访问

4 构造函数

        构造函数是类的同名成员函数,没有返回值,当实例化对象时它会自动被调用,一般负责对类对象进行初始化、分配资源。   

class Test
{
    int* p;
public:
    Test(参数) //  可以重载
    {
        p = new int;
    }
};

① 构造函数必须是public,否则无法创建对象

② 构造函数可以重载,可以有多个版本

③ 带参数的构造函数的调用

        Test t(实参);               //调用有参构造

        Test* p = new Test(实参);   //调用有参构造

        注意:如果没有提供对应版本的构造函数则会报错

④ 默认情况下编译器会给类自动生成一个无参构造,该构造函数什么都不执行,一旦显示地实现了构造函数,则该无参构造不再自动生成,需要时得手动实现

        Test t;             //  可能调用无参构造

        Test* p = new Test; //  可能调用无参构造

⑤ 也可以通过设置有参构造中的默认形参,形成调用无参构造的效果,实际调用的依然是有参构造,但是如果同时存在无参构造时,会产生歧义

⑥ 构造函数没有返回值

⑦ 不要使用malloc去给类对象申请内存,因为它不会自动调用类的构造函数

5 析构函数

        析构函数负责对类对象进行收尾工作,例如:释放类中的资源、保存数据

        当类对象销毁(自动、手动delete)时会自动调用   

class Test
{
    int* p;
public:
    Test(参数) //  可以重载
    {
        p = new int;
    }
    ~Test()   //    析构函数
    {
        delete p;
    }
};

① 析构函数也必须是public

② 析构函数没有参数、没有返回值、不能重载

③ 当类对象的生命周期到期前(栈、堆delete),会自动调用析构函数

④ 构造函数一定会执行,但是析构函数不一定会执行(没用delete)

⑤ 不要使用free释放类对象,它不会调用析构函数

⑥ 如果没有显式地实现析构函数,编译器会自动实现一个什么都不做的析构函数

6 初始化列表

    初始化列表是类中构造函数的一种特殊语法,只能在构造函数中使用

class 类名
{
public:
    类名():成员1(初始化数据),成员2(初始化数据)...
    {
        //  初始化的数据可以是常量、变量
    }
};

① 在C++11之前语法标准中,类的成员变量不可以在定义时设置初始值,而在执行构造函数时成员变量已经定义完成了,因此带有const属性的成员变量就无法在构造函数中通过赋值设置初始值

② 初始化列表的执行先于构造函数,当执行初始化列表时类对象还没创建完成,此时通过初始化列表是C++98之前的语法中唯一一种给const属性的成员变量赋初值的方式,在C++11中初始化列表可以使用形参对成员变量初始化

③ 当形参名与成员名相同时,初始化列表可以自动分辨,可以同名

④ 如果有成员是类类型,它的有参构造可以在初始化列表中被调用

⑥ 如果有多个成员是类类型,它们在初始化列表中的构造函数调用顺序,只跟它们的成员定义顺序有关,与初始化列表中的顺序无关

7 对象的创建和销毁过程

7.1 对象的创建

        ① 给对象划分内存空间(栈/堆)

        ② 执行初始化列表

                根据继承表中的继承顺序,默认执行父类的无参构造函数,也可以调用父类的有参构造,通过 :父类名(参数)

                根据类类型成员的定义顺序,默认执行类类型成员的无参构造函数,也可以调用类类型成员的有参构造,通过 :类类型成员名(参数)

                初始化其他普通成员

        ③ 执行构造函数,申请其他资源

7.2 对象的销毁

        ① 执行析构函数的内容,释放资源

        ② 根据类类型成员定义顺序的逆序,执行它们的析构函数

        ③ 根据继承表的继承顺序逆序,执行父类的析构函数

        ④ 释放对象的内存

成员函数是如何区别调用它的对象?(成员函数中有隐藏的this指针)

    每个对象的内存中只存储了属于它的成员变量,没有存储成员函数指针

    当对象调用成员函数时,编译器会自动把该对象的地址传递给成员函数的一个隐藏参数this指针,this指针参数是专门用于接收对象的地址

    每个成员函数都有隐藏的this指针,this指针相当于拿到了调用对象的地址,就可以通过它访问该对象的成员,以此区分调用成员的对象是哪一个

    this指针虽然是隐藏的,正常情况下不写就代表写了,但有些情况下,可以显式使用

    注意:this指针参数不需要显式定义,直接使用即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就酱77叭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值