面向对象

1. 面向对象学习要求

莫要理解!!!

自我评判标准:

  • 可以自定义类
  • 可以实例化对象
  • 可以通过实例化对象操作成员变量
  • 可以通过实例化对象操作成员函数

2. 什么是面向对象

生活案例喝咖啡:

自己做:

  • 秤豆子 12 - 15G
  • 磨豆子:中等细度
  • 虹吸壶制作
  • 牛奶加热 倒入
  • 拿铁!!!开喝
  • 打扫战场!!!

瑞幸购买:

  • 下单 丝绒拿铁,澳瑞白
  • 取咖啡
  • 走人!!!

面向过程:

  • 亲力亲为,自力更生

面向对象

  • 找合适人,做合适的事!!!

3. 类和对象

对象
雷布斯(军儿哥),任正非,乔布斯(Jobs),勒布朗·詹姆斯,刘翔
黑猫警长,Tom 猫,哆啦A梦,肥波
哮天犬,八公,小七,OD,来福
创新的劳斯莱斯幻影,爽哥柯尼塞格,奇哥克尔维特

类:

  • 对一类事物的统称, 通常包括【属性描述】和【行为描述】

对象:

  • 特殊的,唯一的,独立的个体

4. C++ 中定义类的格式

基本格式

class 类名
{
权限修饰符:
  	成员变量; // Field
    成员函数; // Function
    构造函数; // Constructor
    析构函数; // Destructor
};

明天课程中会讲解在类设计过程中的相关权限修饰问题。【public protected private】

#include <iostream>
#include <cstring>

using namespace std;

class Student
{
public:
    // 成员变量
    char name[32];
    int id;
    short age;
    char gender;

    // 声明成员函数
    void show();
};

// 类外部进行成员函数实现
void Student::show()
{
    cout << "Name : " << name
         << ", ID : " << id
         << ", Age : " << age
         << ", Gender : " << gender
         << endl;
}

int main(int argc, char const *argv[])
{
    Student stu1;

    strcpy(stu1.name, "James");
    stu1.age = 40;
    stu1.id = 1;
    stu1.gender = 'M';

    stu1.show();

    Student *p_stu = new Student;

    stpcpy(p_stu->name, "James");
    p_stu->age = 40;
    p_stu->id = 1;
    p_stu->gender = 'M';

    p_stu->show();

    delete p_stu;

    return 0;
}

5. 构造函数

5.1 构造函数作用
  • 当前类【实例化过程】中,会自动调用对应的构造函数执行。
  • 【实例化过程】当前类得到一个特殊的,唯一的,独立的对象。
  • 构造函数在实例化过程中,明确告知 CPU 当前类型所需内存空间字节数,同时明确当前内存空间对应类型,方便后续使用。
5.2 构造函数格式

格式要求

  • 构造函数的名称是当前类名称。有且只允许构造函数使用类名,是用于明确告知 CPU 当前实例化操作过程中,对应的数据类型是哪一个类型。
  • 构造函数没有返回值占位。
  • 构造函数可以有参数和无参数
类名(用于初始化当前实例化对象的必要参数) 
{
	初始化数据语句;
}
// 例如当前类为 Student
Student(必要参数)
{
    初始化语句;
}
5.3 无参数构造函数

案例:当前类为 Student 类

Student()
{
    // 必要的初始化语句
}
5.4 有参数构造函数

案例:当前类为 Student 类,成员变量有 name age id gender

Student(int id, const char * name, short age, char gender)
{

}
5.5 拷贝构造函数【重点】

案例:当前类为 Student 类,成员变量有 name age id gender

拷贝构造函数参数是当前类引用

Student(Student &stu)
{
  
}
5.6 案例代码

student.h

#ifndef _STUDENT_
#define _STUDENT_

#include <iostream>

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define NAME_LENGTH 32

using namespace std;

class Student
{
public:
    // 成员变量
    char name[NAME_LENGTH];
    int id;
    short age;
    char gender;

    /*
    声明无参数构造函数
    */
    Student();  
    /*
    声明有参数构造函数
    */
    Student(int id, const char * name, short age, char gender);
    /*
    声明拷贝构造函数
    */
    Student(const Student &stu);

    // 声明成员函数
    void show();
};

#endif

student.c

#include "student.h"

/*
实现构造函数,需要保证实例化对象成员变量数据无野值。
*/
Student::Student()
{
    cout << "【Student 类无参数构造函数执行】" << endl;
    /*
    构造函数可以直接使用类内的成员变量
    */
    memset(name, 0, NAME_LENGTH);
    id = 0;
    age = 0;
    gender = '\0';
}

Student::Student(int id, const char *name, short age, char gender)
{
    cout << "【Student 类有参数构造函数执行】" << endl;
    /*
    this 关键字在这里是用于区分成员变量和参数变量。避免出现就近原则问题。
    */
    this->id = id;
    strcpy(this->name, name);
    this->age = age;
    this->gender = gender;
}

/*
拷贝构造函数是将参数 stu 引用对应对象中的成员变量数据
完整的拷贝给当前实例化对象,可以认为是一个【深拷贝】操作
*/
Student::Student(const Student &stu)
{
    cout << "【Student 类拷贝构造函数执行】" << endl;

    id = stu.id;
    strcpy(name, stu.name);
    age = stu.age;
    gender = stu.gender;
}

void Student::show()
{
    cout << "Name : " << name
         << ", ID : " << id
         << ", Age : " << age
         << ", Gender : " << gender
         << endl;
}

data.h

#ifndef _DATA_
#define _DATA_

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

class Data
{
public:
    string key;
    int value;

    Data();
    Data(string key, int value);
    Data(const Data &data);

    void show();
};

#endif

data.c

#include "data.h"

Data::Data()
{
    memset(this, 0, sizeof(Data));
}

/*
: key(key), value(value)
    完成赋值成员变量操作,小括号之外是成员变量名称
    小括号内部是参数变量数据。
    key(key) == 等价于 ==> this->key = key;
*/
Data::Data(string key, int value)
    : key(key),
      value(value)
{
}
Data::Data(const Data &data)
    : key(data.key),
      value(data.value)
{
}

void Data::show()
{
    cout << "Key : " << key
         << ", Value : " << value << endl;
}

6. 析构函数【重点】

6.1 语法特征

任何一个对象,如果占用的内存空间被系统收回,一定会执行析构函数。

定义格式:当前类为 Student 类

~Student();

析构函数格式

  • ~ 开头
  • Student 对应类名
  • () 表示一个函数
6.2 析构函数作用【重中之重】

利用析构函数在对象释放时一定执行的特征,可以释放对象内部申请的相关资源,例如 内存,文件,网络 socket 等

data.h

#ifndef _DATA_
#define _DATA_

#include <iostream>

#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

#define DEFAULT_CAPACITY 10

class Data
{
public:
    char * value;

    Data();
    Data(int init_capacity);
    Data(const char * value);
    Data(const Data &data);
    ~Data();

    void show();
};

#endif

data.cpp

#include "data.h"

Data::Data()
{
    // value 目前仅是一个指针,没有对应的数据存储空间,可以
    // 存储目标存储类型为 char 类型的内存空间首地址
    value = new char[DEFAULT_CAPACITY];
    // 保证内存空间无野值
    memset(value, 0, DEFAULT_CAPACITY);
}

Data::Data(int init_capacity)
{
    value = new char[init_capacity];
    memset(value, 0, init_capacity);
}

Data::Data(const char *value)
{
    size_t length = strlen(value);

    this->value = new char[length + 1];
    memset(this->value, 0, length + 1);

    strcpy(this->value, value);

}
Data::Data(const Data &data)
{
    size_t length = strlen(data.value);

    value = new char[length + 1];
    memset(value, 0, length + 1);

    strcpy(value, data.value);
}

Data::~Data()
{
    /*
    【重中之重】
        以上所有的构造函数,都是使用了 new 申请内存堆区数据空间。
        以上内存空间需要进行必要的释放操作。

    外部行为
        实例化 Data 对象,在外部操作下,仅可以释放当前 Data 类占用内存空间
        无法对内部的 value 申请内存进行处理。
  
    【解决方案】
        可以利用析构函数,对 value 申请的内存空间进行释放操作
    */
    cout << "析构函数执行中~~~~" << endl;
    delete[] value;

    cout << "析构函数执行完毕!" << endl;
}

7. 十二生肖

作业要求

  • 每一个生肖类对应一个 cpp 一个 h 文件,并且配合一个 cpp 文件进行代码调用,建议一个生肖一个文件夹
  • 每一个生肖类必须有三个或者三个以上成员变量,三个或者三个以上成员函数
    • 【成员变量和成员函数要求】十二生肖成员变量和成员函数不得重复,例如 老鼠成员变量 name ,其他类不得有 name 成员变量,牛成员函数吃饭,其他类不得有吃饭函数
  • 每一个生肖必须有三个构造函数,分别对应无参数构造,有参数构造,拷贝构造
  • 每一个生肖必须有对应的析构函数
  • 调用验证要求
    • 每一个生肖必须实例化 3 次,new 申请堆区空间 3 次
    • 并且每一个对象必须操作赋值所有的当前生肖的所有成员变量和成员函数
    • 每一个对象的成员变量必须进行数据展示操作
    • 注意内存释放