3.1、多态与虚析构函数

也是成功完结c++面向对象三个特性中的最后一个特性:多态。

“多态”是指同一名字的事物可以完成不同的功能。

当有虚函数时,基类指针指向基类对象时就使用基类的成员,指向派生类对象时就使用派生类的成员。也就是说,基类指针既可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说多种表现方式,这种现象我们称之为”多态”。

c++提供多态旨在:可以“全方位”的访问所有内容,尤其是成员函数。倘若没有多态,那就只能访问成员变量。

*大的来了*

构成多态的必要条件:

1、必须要有继承关系。

2、继承关系中必须要有同名的虚函数,并且是覆盖关系(函数原型要相同)

3、存在基类的指针,通过该指针调用虚函数。

为了方便,这三要素我们可以简称为,继承 虚函数 指针。

···

我们可以看到这块的析构函数也加上了virtual关键字,我们称其为虚析构函数。

虚析构函数是为了避免内存泄漏,而且是当子类中会有指针成员变量时才会用到。虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数以达到释放子类中堆内存的目的,从而防止内存泄漏

若父类不声明成虚析构函数,当子类继承父类,父类指针指向子类时,此时delete掉这个指针,则只会调动父类的析构函数。

但父类若声明了虚析构函数,delete掉上面这个指针后,会先调动子类的析构函数,再调动父类的析构函数。

class Person
{
protected:
	string name;
	int age;
public:
	Person() {}
	Person(string name, int age) :name(name), age(age) {}
	virtual ~Person()
	{
		cout << "call ~person" << endl;
	}
	virtual void Info()
	{
		cout << "person info:" << this->name << "   " << this->age << endl;
	}
};
class Student:public Person
{
protected:
	double score;
public:
	Student(){}
	Student(string name, int age, double score) :Person(name, age), score(score){}
	~Student()
	{
		cout << "call ~student" << endl;
	}
	virtual void Info()
	{
		cout << "student info:" << this->name << "   " << this->age << "   " << this->score <<endl;
	}

};
int main()
{
	Person* p1 = new Person("xxx", 20);
	p1->Info();
	//Student* s1 = new Student("xm", 11, 99);
	//s1->Info();
	p1 = new Student("xm", 11, 99);
	p1->Info();

    return 0;
}

若没在Info前加virtual则对于p1的改动,此时仍会运行属于person的info函数,但要是加上virtual,在p1变动后则会输出student的info(倘若只在person加也是可以的,因为student是继承的person,但要是反过来那就没用了)

3.2、抽象基类与纯虚函数

在设计时,我们常常希望基类仅仅作为其派生类的一个接口。也就是说,希望用户仅使用这个接口,而希望用户实际地创建一个基类的对象。要做到这点,可以在基类中加入至少一个纯虚函数,来使基类成为抽象类。纯虚函数使用关键字virtual。并且在其后加上=0。

···

当继承一个抽象类时,必须实现所有的纯虚函数,否则继承出的类也将是一个抽象类。创建一个纯虚函数允许在接口中放置成员函数,而不一定要提供一段可能对这个函数毫无意义的代码。同时,纯虚函数要求出的类对他提供一个定义。纯虚函数总是一个“哑巴”函数。

class AbstractDrinking
{
public:
	virtual void boil() = 0;
	virtual void brow() = 0;
	virtual void pour() = 0;
	virtual void add() = 0;

	void make()
	{
		boil();
		brow();
		pour();
		add();
	}
};
class Coffee :public AbstractDrinking
{
public:
	virtual void boil()
	{
		cout << "煮水" << endl;
	}
	virtual void brow()
	{
		cout << "泡咖啡" << endl;
	}
	virtual void pour()
	{
		cout << "咖啡倒入杯子" << endl;
	}
	virtual void add()
	{
		cout << "添加佐料" << endl;
	}
};
class Tea :public AbstractDrinking
{
public:
	virtual void boil()
	{
		cout << "煮水" << endl;
	}
	virtual void brow()
	{
		cout << "泡茶" << endl;
	}
	virtual void pour()
	{
		cout << "茶倒入杯子" << endl;
	}
	virtual void add()
	{
		cout << "添加电脑配件" << endl;
	}
};
void DoBussiness(AbstractDrinking* drink)
{
	drink->make();
	delete drink;
}

int main()
{
    DoBussiness(new Coffee);
    cout << endl;
    DoBussiness(new Tea);

    return 0;
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐