虚函数与纯虚函数

虚函数是在类的继承中出现的一类成员函数,在函数前面标记virtual关键字,效果就是在子类中可以自由的覆写父类中的该成员函数,而不至于在应用多态的概念的时候出现问题
例如:

class Entity
{
public:
	std::string GetName(){return "Entity"};
};

class Player : public Entity
{
private:
	std::string m_name;
public:
	std::string GetName() {return m_name};
};

以上代码如果调用Player类中的函数时对象的类型是以Player来调用的,那它会返回的是m_name,但是如果Player的对象是作为Entity类型的对象被调用的时候则GetName函数则会返回Entity,这在一些函数里面会出现问题,例如:

std::string printName(Entity* e)
{
	std::cout << e->GetName() << std::endl;
}

如果Player类的对象调用以上函数的对象的时候则会输出Entity,而不是对应的m_name,而实际用的时候很多时候需要Player类的对象,因为它们时继承自Entity的,也就是说他们也具有Entity的特征,Player和Entity的关系就像老师和语文老师的关系,这时候我有个函数的输入是老师,那我语文老师也一定可以作为该函数的输入,因为语文老师一定也是老师。但是我输入语文老师的时候希望得到语文老师对应的输出,要让C++意识到我们输入的实际上是语文老师,而不仅仅是老师,那就需要用虚函数,表示在子类里面覆写了这个GetName的成员函数例如:

class Entity
{
public:
	virtual std::string GetName(){return "Entity"};
};

class Player : public Entity
{
private:
	std::string m_name;
public:
	std::string GetName() {return m_name};
};
//虚函数实际上只用把基类中的base function声明为virtual即可,
//子类中的对应的成员函数不需要声明为虚

涉及到虚函数,C++编译的时候实际上会自动生成一个virtual table,通过动态联编(dynamic dispatch)的方式来进行编译,会消耗很少量的额外的内存空间和运算资源(在调用虚函数的时候需要遍历virtual函数表,来找到对应的函数去调用)。

此外,在子类中覆写virtual函数的时候,最好在参数列表后面加上override关键字,说明这个函数是一个覆写过的函数,这样可以增加代码的可读性即:

class Player : public Entity
{
private:
	std::string m_name;
public:
	std::string Getname() override {return m_name;}
};
//override关键字还可以帮助防止一些bug的发生,比如代码中的拼写错误,如GetName这里就拼写错了,这样的话编译器就会报错,可以及时修改

纯虚函数(接口) 纯虚函数允许基类不提供函数的实现,而强制子类去实现自己对应的该函数,称为接口,代码例如:

class Entity
{
public:
	virtual std::string GetName() = 0;//这里的=0就说明这个函数是一个纯虚函数,
    //当实例化其任何一个子类的时候,都必须先实现这个函数,否则无法实例化
};

class Player : public Entity
{
private:
	std::string m_name;
public:
	std::string GetName() override {return m_name;}
};

纯虚函数作为接口,其实可以把包含它的类作为一个参数,用法见cherno的C++系列对应视频的后半Printable类

全部评论

相关推荐

我见java多妩媚:大外包
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务