六、类与对象

这篇博客介绍了面向对象编程的基本特点,包括抽象、封装、继承和多态。详细阐述了类的定义,强调了数据抽象和行为抽象的重要性,并通过实例展示了类的实现。此外,还讨论了对象的初始化,特别是构造函数的类型,如默认构造函数、带参数构造函数和复制构造函数的作用和用法。最后提到了析构函数在对象清理中的角色。
摘要由CSDN通过智能技术生成

1、面向程序的基本特点

  1. 抽象:面向对象方法中的抽象,是指对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程。抽象应该包括两个方面:数据抽象、行为抽象。
  2. 封装:封装就是将抽象得到的数据和行为相结合,形成一个有机的整体。封装的目的是隐藏具体实现,使用户只需要通过外部接口就能够直接访问,不必了解类的细节。这增强了抽象性、数据安全性。
  3. 继承:继承就是将一般与特殊的关系搞清楚。比如:教师类型可以从人类类型中继承。继承允许在保持原始类型的基础上,进行更加具体、详细的说明。
  4. 多态:多态性指的是一段程序能够处理多种数据类型(对象)的能力。多态分为真的多态(数据类型转换、函数重载)、假的多态(包含多态—虚函数、类型参数多态—模板)

2、类的定义

在面向对象程序开发中,程序的基本模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述。

设计类就是设计类型:

  • 此类型的"合法值"是什么?
  • 此类型应该有什么样的函数和操作符?
  • 新类型的对象应该如何被创建和摧毁?
  • 如何进行对象的初始化和赋值?(使用构造函数进行初始化)
  • 对象作为函数的参数如何进行值传递?
  • 谁将实用此类型的对象成员?

类的定义、对象的创建、对象的存储

当定义一个类(数据类型)时,需要定义的数据结构和相关的操作。

#include <iostream>
using namespace std;

class Clock         // 类由class关键字+类型进行定义
{
private:            // 私有成员,只能在类中被访问
    int hour, minute, second;
public:             // 公有成员,可以在类外被访问,函数的具体实现在类外部
    void setTime(int newH=0, int newM=0, int newS=0);// 
    void showTime();
};

void Clock::setTime(int newH, int newM, int newS)
{
    hour = newH;
    minute = newM;
    second = newS;
}

void Clock::showTime()
{
    cout << hour << ":" << minute << ":" << second <<endl;
}

int main(int argc, char const *argv[])
{
    Clock myclock; 
    // 定义钟表类型的变量,该变量的存储空间中只用于存放数据成员,
    // 函数成员不在每一个对象中存储副本,每个函数的代码在内存中只占据一份空间。

    cout << "set first time: " << endl;
    myclock.setTime();  // 对象通过.来访问成员函数
    myclock.showTime();

    cout << "set second time: " << endl;
    myclock.setTime(10, 10, 10);
    myclock.showTime();

    return 0;
}

        一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。  例如,调用myclock.setTime(10, 10, 10) <==> SetMonth(&myclock, 10,10,10),this帮助完成了这一转换 。

        对象的存储空间中值储存了数据成员,没有储存函数成员。

3、对象的初始化

根据类定义的每个对象与基本变量类似,如Clock相当于int,对象myclock相当于变量a。为了保证统一,我们也需要对于对象进行初始化。在特定对象使用结束时,还经常需要进行一些清理工作。这些操作有构造函数和析构函数来完成。

3.1 构造函数

        每一个变量都要占用一定的内存空间,在声明一个变量并初始化时,就意味着在给变量分配内存空间,在其中写入初始变量值。

        对象也是一样的。但是不同类型的对象,数据成员各不相同,编译器不知道如何产生代码来实现初始化,因此就需要我们自己来编写初始化函数——即构造函数。构造函数就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。

  • 函数名与类名相同(构造函数在创建对象是自动调用的,因此名称统一为类名)
  • 不能定义返回值,没有return语句(构造函数的目的是进行初始化,返回值没有意义)
  • 可以有形参,也可以没有形参
  • 可以是内联函数(省去函数调用步骤,加快运行效率)
  • 可以重载(满足不同的初始化要求、有参、无参等)
  • 可以带参数默认值

3.2 构造函数的类型

3.2.1 默认构造函数(无形参构造函数)

由编译系统的生成。触发条件:在定义类中没有定义构造函数,一旦定义的任何构造函数,编译器都不再生成默认构造函数。

// 在类中的声明    
Clock(); //默认构造函数

// 在类外的定义
Clock::Clock():hour(8), minute(8), second(8){} //默认构造函数函数体

3.2.2 普通构造函数(带参数)

// 在类中的声明    
Clock(int, int, int); // 带参构造函数

// 在类外的定义
Clock::Clock(int newH, int newM, int newS)://构造函数函数体
    hour(newH), minute(newM), second(newS){}//大括号前面是初始化列表,大括号内是函数体

 3.2.3 委托构造函数

当在一个类中,多个构造函数的函数体相同,形参列表不同是,此时委托构造函数就可以调用其他构造函数完成初始化。

不使用委托构造函数:

Clock::Clock(int newH, int newM, int newS)://构造函数函数体
    hour(newH), minute(newM), second(newS){}//大括号前面是初始化列表,大括号内是函数体

Clock::Clock():hour(8), minute(8), second(8){} //默认构造函数函数体

使用委托构造函数:

Clock(int newH, int newM, int newS)://构造函数函数体
    hour(newH), minute(newM), second(newS){}//大括号前面是初始化列表,大括号内是函数体
Clock():Clock(0,0,0){}//这里是写在函数体内的,不是外面定义的地方

可以看到,默认构造函数带用了带参的构造函数,完成了初始化,实现了代码的重用。

3.2.4 复制构造函数

        复制构造函数是一种特殊的构造函数,目的是实现对象之间的直接幅值,就像整型变量一样可以直接赋值。复制构造函数的形参是对象的引用(不然会造成递归定义),例如Clock& myclock。系统可以生成一个默认的复制构造函数——创建一个除地址外完全一样的对象。

// 类内拷贝构造函数的声明
Point(Point& p);
// 如果拷贝构造函数原型为Point(Point p);,则在进行参数传递过程中需要调用拷贝构造函数
// 这样就造成了递归调用

// 类外拷贝构造函数的定义
Point::Point(Point& p)
{
    x = p.x;
    y = p.y;
}

复制构造函数被调用的三种情况

  • 定义一个对象时,以本类另一个对象作为初始值,发生复制构造;
  • 如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造。
  • 如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化为一个临时无名对象,传递给主调函数,此时发生复制构造。这种情况也可以通过移动构造避免不必要的复制。

4、对象的清理

析构函数作用是负责对象被删除前的一些清理工作

在对象生存期即将结束时,析构函数将会被调用

析构函数不接受任何参数,如果不进行显示说明,系统也会生成一个函数体为空的隐含析构函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值