C++多态实现——虚函数

C++多态实现——虚函数

参考文章:虚函数–https://blog.csdn.net/LC98123456/article/details/81143102

C++的多态性用一句话概括就是:
在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。

如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数,当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数。

我们先来看一段代码

#include	

class People{
public:
    People()
    {
        std::cout << "People" << std::endl;
    }
    ~People()
    {
        std::cout << "~People" << std::endl;
    }
	void doWork(){
         std::cout << "打豆豆" << std::endl;
     }
};

class Student : public People{
public:
	void doWork(){
         std::cout << "打游戏" << std::endl;
     }
};

class Worker : public People{
public:
	void doWork(){
         std::cout << "搬砖" << std::endl;
     }
};

int main()
{
    // 基类指针
    People *peo;
    // 指向基类对象
    peo = new People;
    peo->doWork();
    delete peo;
    // 指向子类对象
    peo = new Student;
    peo->doWork();
    delete peo;
    peo = new Worker;
    peo->doWork();
    delete peo;
    
    getchar();
    return 0;
}


可以用基类指针指向子类对象,但不可以反过来,即 Student* stu = new People; 是错的;

结果:

在这里插入图片描述

我们做一点的转化

int main()
{
    // 基类指针
    People *peo;
    peo = new People;
    Student* stu;
    // 强转
    stu = (Student*) peo;
    stu->doWork();
    delete stu;
    
    getchar();
    return 0;
}
结果

在这里插入图片描述

学习笔记:

函数隐藏状态下,不关心指针存的是谁的地址,而关心指针类型,指针类型是啥,调用啥的成员函数,即People* 类型指针,调用 People的成员函数,Student* 调用 Student的成员函数,与 new 的对象无关;

一、虚函数

为了方便使用多态特性,我们常常需要在基类中定义虚函数

#include	

class People{
public:
    People()
    {
        std::cout << "People" << std::endl;
    }
    ~People()
    {
        std::cout << "~People" << std::endl;
    }
    // 虚函数
	virtual void doWork(){
         std::cout << "打豆豆" << std::endl;
     }
};

class Student : public People{
public:
    // 函数覆盖/函数重写
	void doWork(){
         std::cout << "打游戏" << std::endl;
     }
};

int main()
{
    People* peo;
    peo = new Student;
    peo->doWork();
    delete peo;
    peo = new People;
    peo->doWork();
    delete peo;
    
    getchar();
    return 0;
}
结果:

在这里插入图片描述

学习笔记:
  • 当基类的函数加上 virtual关键字变成虚函数之后,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数;
  • 只关心指针存放的是(new的是谁)谁的地址,而不关心其类型;
  • 定义一个基类指针,再根据需要 new派生类对象给基类指针动态赋值;
  • 函数覆盖/函数重写:在派生类和基类中,函数名和参数都相同,并且基类的函数带有virtual关键字

二、纯虚函数

#include	

class People //抽象类{
public:
	virtual void doWork() = 0;  //纯虚函数
};

class Student : public People{
public:
	void doWork()//如果子类不重写父类的虚函数,那么这个子类也是抽象类
	{
		std::cout << "打王者荣耀" << std::endl;
	}
};

int main()
{
	People p;//不允许实例化
	Student s;//子类可以实例化
 
   getchar();
	return 0;
}
学习笔记:
  • 纯虚函数格式:虚函数 = 0; eg: virtual void doWork() = 0;
  • 含有纯虚函数的类为抽象类, 抽象类不允许实例化;
  • 派生类需要重写虚函数,如果不重写,则该派生类也是抽象类;

三、虚析构

常常把析构函数设置成虚函数
先来看一段代码&结果

#include 

class People{
public:
    People()
    {
        std::cout << "People" << std::endl;
    }
    ~People()
    {
        std::cout << "~People" << std::endl;
    }
	void doWork() = 0;
};

class Student : public People{
public:
    Student()
    {
        std::cout << "People" << std::endl;
    }
    ~Student()
    {
        std::cout << "~People" << std::endl;
    }
	virtual void doWork(){
         std::cout << "打游戏" << std::endl;
     }
};

int main()
{
    People* peo = new Student;
    peo->doWork();
    delete peo;
    
    getchar();
    return 0;
}
结果

在这里插入图片描述

分析

显然我们发现,在基类指针指向派生类对象后,在释放空间时,不会走派生类的析构函数;(当派生类指针只想自己的对象时,会调用派生类的析构)

解决

把基类析构函数设置成虚函数

class People{
public:
    People()
    {
        std::cout << "People" << std::endl;
    }
    virtual ~People()
    {
        std::cout << "~People" << std::endl;
    }
	void doWork() = 0;
};
结果

在这里插入图片描述

学习笔记

为什么要加虚析构,会有问题吗? 基类指针指向派生类对象后,基类的析构函数不定义成虚函数,在释放内存时,派生类的析构函数不会被调用,如果在派生类的析构函数里面有释放资源的操作,那么就会造成资源的泄露;
为什么默认不是虚析构 虚函数?会在类中产生一个虚指针,浪费空间。

四、虚指针

五、虚函数列表

https://www.cnblogs.com/hushpa/p/5707475.html

https://blog.csdn.net/qq_36359022/article/details/81870219

六、多态实例

http://c.biancheng.net/cpp/biancheng/view/243.html

你可能感兴趣的:(C++,多态,c++,抽象类,面向对象编程,指针)