C++多态特性:virtual关键字的使用

1. C++多态

1.1 多态的构成条件

  多态是指不同继承关系的类对象,调用同一函数时产生了不同的行为。多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
  C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。比如Student类继承自Person类,Person对象在买票这一行为上需要全价,而Student对象买票半价。

在继承中要构成多态还有两个条件

  • 必须通过父类的指针或者引用调用虚函数。
  • 被调用的函数必须是虚函数,且派生类必须对父类的虚函数进行重写。

1.2 virtual关键字

  Virtual是C++ 面向对象机制中很重要的一个关键字。只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数。virtual实现多态的底层逻辑:

  • 没有virtual关键字时:指定调用父类的print
  • 有virtual关键字时 : 调用一个地址,这个地址可以是父类的print也可以是子类的print,需要看你传入的是哪个类的对象。

2. virtual关键字的使用

2.1 防止内存泄漏

  下面看一组比较简单的类继承代码,并确认是否存在内存泄漏问题。

// TestVirtualKey.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include 
using namespace std;

class Person
{
public:
	Person(int nSex)
	{
		this->m_nSex = nSex;
		cout << "Person()构造函数!" << endl;
	}

	virtual ~Person()
	{
		cout << "~Person()析构函数!" << endl;
	}

	virtual void print()
	{
		cout << m_nSex << endl;
	}

protected:
	int m_nSex;// 性别
};

// 派生类Teacher
class Teacher : public Person
{
public:
	Teacher(int nSex, int nAge):Person(nSex)
	{
		this->m_nAge = nAge;
		m_nData = new int[64];
		cout << "Teacher()构造函数!" << endl;
	}

	~Teacher()
	{
		delete[] m_nData;
		cout << "~Teacher()析构函数:删除指针变量!" << endl;
	}

	void print()
	{
		Person::print();
		cout << m_nAge << endl;
	}

private:
	int m_nAge; // 年龄
	int* m_nData;
};

int main()
{
	Person* personA = new Teacher(0,18);
	//personA->print();
	delete personA;
	personA = nullptr;

	return 0;
}

  粗略看是没有问题的,但由于继承类Teacher中存在指针变量并且已经分配了内存,此时就要小心指针变量的内存是否被释放的问题了。运行一下看:

Person()构造函数!
Teacher()构造函数!
~Person()析构函数!

发现没有执行Teacher()析构函数,此时就产生了内存泄漏。

  我们把基类Person()析构函数前加上virtual关键字,也就是改为:virtual ~Person()。再次运行:

Person()构造函数!
Teacher()构造函数!
~Teacher()析构函数:删除指针变量!
~Person()析构函数!

这次执行Teacher()析构函数,此时就防止了内存泄漏。同理print()加上virtual关键字也是一样的效果。

结论:基类的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的。

2.2 纯虚函数

  纯虚函数一般用在基类中,并且基类作为工具类使用,即不实现相关的功能函数,所有的功能实现都放在子类中进行实现。父类中含有纯虚函数一般目的都是为了实现接口类,包含纯虚函数的类被称为抽象类,例如下面所示:

virtual void print() = 0

纯虚函数有几个需要注意的特点:

  1. 含有纯虚函数的类被称为抽象类,不能创建对象;
  2. 虚函数可以直接使用,也可以被子类重写之后以多态的形式调用,而纯虚函数必须在子类中实现该函数才能使用。

简单总结一下:如果基类中的函数没有任何实现的意义,那么可以定义为纯虚函数

3. 知识总结

  1. 父类指针或引用可以直接指向子类对象;子类指针也可以指向父类对象,但没必要;
  2. C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;
  3. virtual关键字修饰的函数称为虚函数,virtual是实现多态的关键;
  4. 虚函数的目的是提供一个统一的接口,被继承的子类重写,以多态的形式调用;
  5. 如果基类函数没有任何实现的意义,那么可以定义为纯虚函数virtual … = 0;
  6. 含有纯虚函数的类被称为抽象类,不能创建对象;
  7. 虚函数可以直接被使用,也可以被子类重写以后以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用。

你可能感兴趣的:(C++学习基础,C++每日一问,c++,C++多态,C++关键字virtual)