虚函数
#include <iostream>
#include <string>
class Entity
{
public;
std::string GetName(){return Entity};
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
std::string GetName(){return m_Name};
};
int mian()
{
Entity* e = new Entity();
std::cout<<e->GetName()<<std::endl;
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
std::cin.get();
}
打印出
Enitiy
少少杰是小白
讲解代码之前先知道“std::” 是什么意思。
首先“::”表示为作用域。举个栗子AB是两个类
1、A::member就表示类A中的成员member。
2、B::member就表示类B中的成员member。
std是一个标准类存放在<iostream>中,包含cin、cout函数以及C++标准程序库中的所有标识符。
所以加上std::就是在这个命名空间下的类型,可以减少代码的奇异性。
还有一件事构造函数后的":"表示对构造函数初始化赋值。
明白以上两点再来解释代码,Entity类中GetName函数返回Entity这个名。Player类中GetName函数返回我们自己的命名。然而由于多态的问题,Player类既是Palyer类又是Entity类,有相同函数那么就会出现问题,使用Player还是Entity中的GetName呢?
#include <iostream>
#include <string>
class Entity
{
public;
std::string GetName(){return Entity};
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
std::string GetName(){return m_Name};
};
int mian()
{
Entity* e = new Entity();
std::cout<<e->GetName()<<std::endl;
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
Entity* ptr = p;
std::cout<<ptr->GetName()<<std::endl;
std::cin.get();
}
我们实际意义上希望的是ptr指向Player类并调用其GetName函数,然而看控制台打印出
Enitiy
少杰是小白
Entity
我们想象的Player类中的p传给ptr,从而使用Player下的GetName,然而由于我们设置了Entity* ptr导致编译器优先确定了ptr属于Entity类中进而使用了Entity下的GetName,这就是原因所在。
我们在重复函数前加入“virtual”
#include <iostream>
#include <string>
class Entity
{
public;
virtual std::string GetName(){return Entity};
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
std::string GetName(){return m_Name};
};
int mian()
{
Entity* e = new Entity();
std::cout<<e->GetName()<<std::endl;
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
Entity* ptr = p;
std::cout<<ptr->GetName()<<std::endl;
std::cin.get();
}
此时打印台就是
Enitiy
少杰是小白
少杰是小白
我们成这个GetName这个重复函数为虚函数,为了方便代码的可读性我们在Player类中GetName加入“override”体现被复写的概念,为了方便读代码。
#include <iostream>
#include <string>
class Entity
{
public;
virtual std::string GetName(){return Entity};
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
std::string GetName()override{return m_Name};
};
int mian()
{
Entity* e = new Entity();
std::cout<<e->GetName()<<std::endl;
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
Entity* ptr = p;
std::cout<<ptr->GetName()<<std::endl;
std::cin.get();
}
虚函数创建了一个v表,将已有的函数与重复的函数存放在一起,在不同情况下进行分配。
纯虚函数
纯虚函数定义一个基类未实现的函数,然后强制子类去实现这个功能。我们称其为“接口”,相当于在基类(父类)建立一个模版方便调用,这在代码中十分常见。
#include <iostream>
#include <string>
class Entity
{
public;
virtual std::string GetName() = 0;
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
std::string GetName()override{return m_Name};
};
int mian()
{
Entity* e = new Entity();
std::cout<<e->GetName()<<std::endl;
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
std::cin.get();
}
virtual std::string GetName() = 0;
我们将其赋值为0,就说明我们建立一个纯虚函数。当建立了纯虚函数,我们必须要在子类下实现这个函数,否则我们将无法对父类Entity创建实例。
我们运行以上程序会发现报错,我们不可以对其创造实例了,但是子类Player依旧可以运行。
我们如果让Player类中的GetName函数注释掉,就是说Palyer类没有实现纯虚函数那么
#include <iostream>
#include <string>
class Entity
{
public;
virtual std::string GetName() = 0;
};
class Player:Public Entity
{
private:
std::string m_Name;
public;
Player(const std::string& name):m_Name(name){};
// std::string GetName()override{return m_Name};
};
int mian()
{
Player* p = new Player("少杰是小白");
std::cout<<p->GetName()<<std::endl;
std::cin.get();
}
我们可以看到连“少杰是小白”都打不出来了。
这就是C++中的接口,也就是纯虚函数。他可以让那个只有你实现了虚函数,才可以使用这个实例,就像是开关一样。