c++第八天-多态

  1. 虚函数
  2. 虚析构函数
  3. 纯虚函数与抽象类

多态实现的条件:(1)公有继承 (2)派生类重写基类虚函数 (3)基类指针/引用指向派生类对象

虚函数不能是构造函数,不能是静态函数,不能是友元函数,只能是普通的成员函数。

其中,绑定的含义是什么?

绑定分为两类,一类是静态绑定,一类是动态绑定

静态绑定:在编译阶段,普通成员函数、全局函数、重载函数这些都是静态绑定

动态绑定:在运行阶段,程序才能确定函数调用对应的具体函数,只有virtual声明的虚函数,并且用基类指针引用调用时,此案呢个发生动态绑定。

绑定就是确定函数调用到底会执行哪一个函数体的过程。

静态绑定就是在编译时绑定,动态绑定就是在运行时绑定。

绑定就是“函数调用和函数实现之间的对应关系是何时确定”的过程。

c++第八天-多态_第1张图片

 基类声明了虚函数,产生虚函数表,将虚函数放入。类多一个隐含的虚函数指针,指向虚函数表。派生类继承时,会更新虚函数指针,指向自己的虚函数表,派生类重写的虚函数会放入派生类的虚函数表中。基类指针/引用指向派生类对象的时候,通过指针/引用调用虚函数时,会先通过派生类对象的虚函数指针到虚函数表中查找,如果有就会调用派生类的虚函数。

通过对象名无法实现多态。

#include
using namespace std;

class A{
public:
    virtual void func() {cout << "A::func" << endl;}
};

class B : public A{
public:
    void func() {cout << "B::func" << endl;}
};

int main()
{
    A* pa = new B();
    pa->func();     //多态,基类用指针调用派生类的虚函数

    A a;
    B b;
    a = b;
    a.func();   //不是多态,对象名无法调用派生类的成员函数,C++语法规则
    return 0;
}

补充:override/final

因为基类中声明了虚函数,这个函数在派生类中即使不加virtual,它在派生类中仍然是虚函数。所以在类的多层继承的情况下,一个成员函数很难看出是不是虚函数,可以通过override确保这个函数在某个基类中声明过虚函数,那么他就是虚函数。

class A{
public:    
    virtual void func() {cout << "A::func()" << endl;}
    void show() {cout << "A::show" << endl;}
};

class B : public A{
public:
    void func() override {cout << "B::func" << endl;}
    void show() override {cout << "B::show" << endl;}
};

final: 修饰类时表示类不能被继承;修饰虚函数时表示虚函数不能被重写。

虚析构函数

         构造函数不能声明为虚函数,原因是构造函数在对象创建完之前调用的,此时还没有虚函数表和虚函数指针。

        析构函数在对象释放时调用,此时对象已经创建完成了,所以它有条件声明为虚函数。而且,应该声明成虚函数。

        如果析构函数不是虚函数的话,基类指针指向派生类对象,通过基类指针释放对象空间时,只会调用基类析构函数,而不会调用派生类析构函数,这样会导致派生类中的动态内存单元不被释放。

 

#include
using namespace std;
class Base {			//基类Base
public:
	virtual ~Base();		//虚析构函数
};

Base::~Base() {
	cout << "Base类析构函数" << endl;
}

class Derive :public Base {		//派生类Derive公有继承Base类
public:
	~Derive();		//虚析构函数
};

Derive::~Derive()
{
	cout << "Derive类析构函数" << endl;
}

int main() {
	Base* pb = new Derive;		//基类指针指向派生类对象
	delete pb;
	return 0;
}

纯虚函数与抽象类

当基类非常抽象时,它的函数代码不好实现,不能只写出函数原型,而不写代码,定义这个函数的目的,是为了规范它的所有派生类都必须要有的函数,它的作用相当于接口。

纯虚函数定义的语法:

virtual 函数返回值类型函数名(参数列表) =  0

如果一个类中包含纯虚函数,这样的类称为抽象类。

抽象类的作用就是为了定义接口,方便实现多态。

抽象类不能创建对象,只能作为基类派生。

抽象类中如果有多个纯虚函数,派生类没有全部实现,此时派生类仍然是抽象类。

 

#include
using namespace std;

class Animal{   //动物类Animal
public:
    virtual void speak() = 0;   //纯虚函数
    virtual void eat() = 0;     //纯虚函数
    virtual ~Animal();          //析构函数
};

Animal :: ~Animal()
{
    cout << "调用Animal析构函数" << endl;
}

class Cat : public Animal{
public:
    void speak();
    void eat();
    ~Cat();
};

void Cat :: speak() {cout << "小猫喵喵叫" << endl;}
void Cat :: eat() {cout << "小猫吃鱼" << endl;}
Cat :: ~Cat() {cout << "调用Cat析构函数" << endl;}
class Rabbit :public Animal {	//兔子类Rabbit公有继承Animal类
public:
	void speak();		//声明speak()函数
	void eat();		//声明eat()函数
	~Rabbit();		//声明析构函数
};
void Rabbit::speak() { cout << "小兔子咕咕叫" << endl; }
void Rabbit::eat() { cout << "小兔子吃白菜" << endl; }
Rabbit::~Rabbit() { cout << "调用Rabbit析构函数" << endl; }


int main() {
	Animal* pa = new Cat;	//定义基类指针pC指向Cat类对象
	pa->speak();		//通过pC指针调用speak()函数
	pa->eat();		//通过pC指针调用eat()函数
	delete pa;		//释放指针pC指向的空间
	pa = new Rabbit;	//定义基类指针pR指向Rabbit类对象
	pa->speak();		//通过pR指针调用speak()函数
	pa->eat();		//通过pR指针调用eat()函数
	delete pa;		//释放pR指向的空间
	return 0;
}

你可能感兴趣的:(c++面向对象,c++,开发语言)