天天看点

面向对象编程,类与对象的详细解答(构造、析构函数)一、面向对象编程二、类和对象三、类的定义与实例化四、构造函数与初始化列表五、对象创建过程六、类的声明与实现分开六、析构函数六、缺省的析构函数,构造函数

一、面向对象编程

​ 面向过程编程:关注于解决问题的方法、步骤。

​ 面向对象编程:关注于谁能解决问题(类),以及解决问题需要的数据(成员变量),以及解决问题需要的技能(成员函数)。

​ 抽象:想象出一个能解决问题的对象(观察、想象),分析出解决问题需要的属性(成员变量)和行为(成员函数)。

​ 封装:把抽象的结果分装成类(数据类型),并设置上相应的访问权限。

​ 使用封装的类实例化对象,调用对象的成员函数与成员变量相互作用达到解决问题的目的。

​ 继承:在解决问题之前,先寻找有没有能解决部分问题的类,如果有则把旧的类继承并再拓展,然后缩短解决问题的时间、降低解决问题的难度。

​ 多态:对象的多种形态,当对象发出一条指令,对象会根据自身的情况作出独特的响应。

二、类和对象

​ 1、把抽象结果封装成一个数据类型(结构、类)

​ 2、类就是一种数据类型

​ 简单类型:只能表示一个变量,C/C++内建数据类型

​ 数组类型:类型相同的多个变量

​ 结构类型:不同类型的多个变量

​ 类类型:不同类型的多个变量、函数

​ 3、对象:类这种数据类型创建出来的实例,相当于结构变量

三、类的定义与实例化

1、类的一般形式

class 类名:继承方式 父类名
{
访问限定符:
    成员变量;
访问限定符:
    //构造函数
    类名(形参列表)
	{
    	函数体;
	}
    //成员函数;
    返回值 函数名(形参列表)
	{
    	函数体;
    	return val;
	}
};
           

2、访问限定符

​ public:共有成员,可以在任何位置访问。

​ protected:受保护成员,只能在自己的成员函数中和子类的成员函数中访问。

​ private:私有成员,只能在自己的成员函数访问。

注意:在class中成员的默认是private,在struct中成员默认是public。

​ 一般把成员变量设置为private,把成员函数设置为public。

3、对象的创建方法

​ 在栈上创建方法

​ 类名 对象;

​ 类名 对象数组名[对象数量];

​ 在堆上创建

​ 类名* 对象指针 = new 类名;

​ 类名* 对象指针 = new 类名[对象数量];

四、构造函数与初始化列表

1、什么是构造函数

​ 对象创建时自动调用的函数叫构造函数,负责完成一些准备工作。

2、无参构造

​ 一个类中至少要有一个构造函数,如果不显示实现,编译器则自动生成一个没有参数的构造函数,也叫无参构造。

​ 如果显式实现了构造函数,则无参构造不再生成,为了避免出错,最好在显式实现一个什么都不做的无参构造。

3、有参构造

​ 创建对象可以附带一些数据给构造函数,用于初始化成员变量,这样就必须显式实现带参数的构造函数,构造函数的参数就是创建对象时传递的数据。

注意:可以给有参构造设置默认参数,这样可以达到无参构造的效果。

​ 类名 对象(实参);

​ 类名* 对象指针 = new 类名(实参);

4、单参构造

​ 如果构造函数只有一个,如此参数的类型与类型之间有类型提升的特性。

​ 如果不想有类型提升的功能,可以在单参构造前加explicit关键字,禁止单参构造的类型提升。

class Test
{
    public:
    Test(int n)
    {
        
    }
};
Test t = 10;//自动调用单参构造而不会出错。
           

5、初始化列表

构造函数(参数):成员1(参数1),成员2(参数2)//初始化列表
{
    
}
           

初始化列表就是一种给类的成员变量初始化的一种语法格式。

特点:

​ 1、可以区分相同的参数和成员变量。

​ 2、可以给类类型的成员变量或构造函数传递参数。

​ 3、还可以给父类的构造函数传递参数

​ 4、常属性的成员只能在初始化列表中赋值

五、对象创建过程

  1. 分配类对象所需要的内存空间,无论栈或堆
  2. 传递实参调用构造函数,完成如下任务:
    1. 执行初始化列表
    2. 根据继承表继承顺序调用父类构造函数
    3. 根据成员变量的定义顺序调用成员变量的构造函数
    4. 执行构造函数中的代码

六、类的声明与实现分开

1、在头文件中声明类

class 类名:继承方式 父类
{
    成员变量;
    ...
public:
    类名(形参列表);
    返回值 成员函数(形参列表);
    ...
}
           

2、在源文件中实现类的成员函数

#include "声明类的头文件"
类名::类名(形参列表)
{
}
返回值 类名::成员函数(形参列表)
{
    函数体;
    return val;
}
           

3、使用类只需要包含类的头文件,然后使用者与类的源文件目标文件一起合并即可。

注意:如果类中的内容不多,在头文件中全部实现。

六、析构函数

1、什么是析构函数

​ 与构造函数一样也是一种特殊的成员函数,它会在对象释放的时候自动调用,负责一些收尾工作,如:保存数据、释放资源等。

2、函数格式

~类名(void)
{
    
}
           

3、析构函数的任务

​ 负责释放在构造函数中获取到的所有资源。

​ 执行过程:

​ 1、先执行析构函数本身代码

​ 2、调用成员变量的析构函数

​ 3、调用父类的析构函数

  • 注意:析构函数与构造函数的执行顺序刚好相反
#include <iostream>
using namespace std;

class Test
{
public:
	Test(void)
	{
		cout<<"我是构造函数"<<endl;
	}
	~Test(void)
	{
		cout<<"我是析构函数"<<endl;
	}
};

void func(void)
{
	Test* t = new Test;
	cout<<"-------"<<endl;
	delete t;
}
int main(int argc,const char* argv[])
{
	int n=3;
	while(n--)
	func();
}
           

六、缺省的析构函数,构造函数

1、 定义

在设计一个类时,如果没有显示实现构造函数与析构函数,编译器 会自动生成它们,也叫缺省的构造和析构函数。

但生成的并不是真正语法意义上的函数,而是功能意义上的函数。

编译器做为可执行指令的生成着,它有能力直接生成某些功能的二进制指令,不需要借助语言上的函数完成某些任务。

2、 什么时候需要显示实现构造函数

  1. 有成员需要初始化
  2. 需要一些参数做一些准备工作
  3. 需要在对象使用之前准备一些资源.如:申请一些堆内存

3.、什么时候需要显示实现析构函数

缺省的析构函数会自动释放编译器能看得到的所有资源。如:成员变量,类成员,父类

  1. 保存一些数据
  2. 成员变量中有指针,且指向堆内存。

继续阅读