c++基础复习(3)

复习点:一、封装、继承和多态  二、重载、重写(覆盖)和隐藏   三、虚函数   四、malloc、free和new、delete的区别

封装、继承和多态

1、封装

封装是面向对象方法的重要原则,就是把对象的属性和服务结合成一个独立的系统单位,并且尽可能隐藏对象的内部细节。结合到c++中,这个独立的系统单位就是类,类需要有高聚合和低耦合性,即内部的属性和服务尽可能的联系紧密,而对外部只提供一些必要的接口。让使用的人不必清除类内部是如何实现的。

2、继承

继承是面向对象技术能够提高软件开发的重要原因之一。通过继承可以实现“代码复用”,从而有效的较少的代码的编写量。

3、多态

多态性是指在一般的类中定义的属性或行为,被特殊类继承后,可以具有不同的数据类型或表现出不同的行为。

多态分为:静态多态和动态多态。其中静态多态通过模板和重载实现,而动态多态则是通过虚函数机制实现。

静态多态:即在编译时,就决定了程序在执行时去运行具体那个函数。如:运算符重载,函数重载等。

动态多态:即在程序执行时,才能确定具体执行的时那个函数。如:虚函数。

重载、重写(覆盖)和隐藏 

1、重载:是指在同一访问区内(同一个类)被声明的具有不同参数列表的同名函数,在函数调用时可以通过参数列表来确定调用的对象,重载不关心函数的返回值类型。即同一类中,同名不同参。

参数列表不同主要表现在以下几个方面:

(1)参数的个数不同

(2)参数顺序不同

(3)参数类型不同

这里需要注意函数返回值类型的不同,并不是重载。但函数声明为const是可以被认定为重载的。const对象只能调用cosnt方法,非const对象优先调用非const方法。

为什么在c语言中不支持函数重载?

在函数编译时,会给每个函数设置一库函数名。而在c语言中,这个库函数名的生成仅仅只和函数名有关。假设一个函数的声明为

int fun(int n,char m);

在c中的库函数名称为_fun,即仅仅之和函数名存在关系。

而在c++中的库函数名称为_fun_int_char,即和函数名和参数列表有关(注意:和函数返回值无关)。

所以:在C语言中如何定义同名函数,编译器是没有办法区分的,所以C语言中无法重载。

2、重写(覆盖):在派生类中重载对基类中的函数重新进行了实现,其函数名、返回值、参数列表都必须和基类中被重写的函数一致,这样就可以实现通过基类指针或引用来访问派生类中重写了的函数了。

3、隐藏:又被称为同名隐藏,指在派生类中实现了和基类的同名的方法,这样派生类的对象就会访问到派生类中实现的方法,而不是基类中的方法。

#include <iostream>
using namespace std;
class Test
{
public:
	int fun(int n)    
	{
		cout << "parent int n=" << n << endl;
		return 0;
	}
	char fun(char n)   //重载  同一个类的同名不同参的函数
	{
		cout << "parent char n=" << n << endl;
		return 0;
	}
	virtual int fun1(int m)
	{
		cout << "parent int m=" << m << endl;
		return 0;
	}
};
class TestChild :public Test
{
public:
	double fun(double n)//同名隐藏 派生类隐藏了基类的方法
	{
		cout << "child double n=" << n << endl;
		return 0;
	}
	int fun1(int m)  //重写(覆盖)派生类覆盖了基类的方法
	{
		cout << "child int m=" << m << endl;
		return 0;
	}
};
int main()
{
	Test test;
	TestChild testChild;
	
	test.fun(2);
	test.fun('c');
	testChild.fun(1.1);
	Test *pTest = new Test();
	pTest->fun1(15);
	pTest = new TestChild();//通过父类指针使用基类的函数,可以写virtual,也可以不写
	pTest->fun1(20);
	return 0;
}

重载、重写(覆盖)和隐藏的区别?

(1)重载在同一个类中,重写和隐藏是在基类和派生类中。

(2)重写(覆盖)派生类和基类的函数名,返回值、参数列表必须全部一致,而隐藏只需要和基类函数同名即可。

(3)重写(覆盖)基类必须为虚函数。

虚函数(virtual)

上面提到动态多态主要通过虚函数机制实现,这里介绍以下虚函数。和普通的函数声明方式相同,只要在函数的返回值前加上virtual关键字,该函数就为虚函数,即virtual 函数类型 函数名(形式参数)

虚函数的作用:允许通过基类的指针或引用来访问基类和派生类的同名函数

1、虚成员函数

具体来看一下代码:

#include <iostream>
using namespace std;
class Teacher
{
public:
	virtual void work()
	{
		cout << "上课" << endl;
	}
};

class MathTeacher :public Teacher
{
public:
	virtual void work()
	{
		cout << "数学课" << endl;
	}
};

class ChinsesTeachar :public Teacher
{
public:
	virtual void work()
	{
		cout << "语文课" << endl;
	}
};

class EnglishTeachar :public Teacher
{
public:
	virtual void work()
	{
		cout << "英语课" << endl;
	}
};

int main()
{
	cout << "上课啦!!!" << endl;
	MathTeacher tea;
	tea.Teacher::work();
	tea.MathTeacher::work();//没有虚函数只能这样调用基类的函数
	//定义一个指针数组
	Teacher** teacher = new Teacher*[3]();
	MathTeacher math;
	EnglishTeachar english;
	teacher[0] = new MathTeacher();
	teacher[1] = new ChinsesTeachar();
	teacher[2] = new EnglishTeachar();
	
	for (int i = 0; i < 3; ++i)
	{
		teacher[i]->work();
	}
	return 0;
}

可以通过基类的指针区访问派生的方法。

2、虚析构函数

在c++中不能声明虚构造函数,但可以声明虚析构函数。虚析构函数的作用就是为了:防止因基类指针指向派生类的对象而造成的内存泄漏问题。

上面提到,通过基类指针可以指向派生类的对象,从而使用派生类方法。如果基类的析构函数不是虚函数的话,编译器在执行时,就不会动态绑定,从而就是导致编译器指调用了基类的析构函数,而没有调用派生类的析构函数,这样就会有潜在的内存泄漏的风险。而通过虚析构函数可以解决这一问题。

构造函数为什么不能是虚函数?

因为虚函数的执行依赖于虚函数表,而虚函数表的初始化是在构造函数中完成,所以构造函数无法声明为虚函数。

为什么默认的析构函数不是虚函数?

虚函数的工作是基于虚函数表的,而虚函数表时需要消耗空间的。而在程序中又不一定又继承,所以默认的析构函数不是虚函数。

总结:一个类的构造函数无法被声明为虚函数,而析构函数则可以声明为虚函数。如果程序中存在继承那么最好将析构函数设置为虚析构函数。

3、纯虚函数

//声明格式:virtual 函数类型 函数名( 参数列表 ) =0; 可以没有函数体的实现
virtual int fun(int n,int m)=0;

拥有纯虚函数的类,为抽象类。抽象类不能实例化对象。抽象类的子类会自动继承该纯虚函数,如果子类中任然没有实现该方法,那么该子类任然为纯虚函数。

malloc、free和new、delete的区别

1、malloc、free是c语言中的函数;new、delete是c++的运算符。

2、malloc在申请空间是地址的返回值是void*,需要用户转化;而new的返回值为申请时的类型,不需要转化。

3、malloc在调用时必须指定空间的大小;new在调用时会自动计算大小。

4、malloc只能申请基本类型和自定义的类型的空间,而new可以为类申请空间。即malloc不能调用构造函数,而new可以。

5、在空间申请失败时,malloc会返回NULL,而new会报错。

6、malloc和free工作在堆(操作系统概念)上,而new和delete工作在自由存储区(c++内存分区概念)上。

7、malloc和free时c语言中的函数不允许重载,而new和delete时c++的运算符所以允许重载。

这里需要注意:c和c++中的内存分配还不是完全一样的。

c中的内存分配:栈、堆、静态存储区、常量存储区、程序代码区

c++中的内存分配:栈、堆、自由存储区、静态存储区、常量存储区

在这里需要记住:什么是堆?即malloc和free操作的空间。什么是自由存储区?即new和delete操作的空间

c++中的自由存储区是一个抽象的概念的,它并不一定就是堆。new和delete的底层时借助malloc和free实现的而malloc和free操作的对象就是堆,所以一般情况下自由存储区就是堆,但new和delet属于运算符,可以重载,这样自由存储就可以时别的空间了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值