C++ 虚函数

一段代码

#include"stdafx.h"
#include<iostream>
#include<string>
using namespace std;

class Character
{
public:
    void ToString()
    {
        cout << "I'm character" << endl;
    }
};

class Player : public Character
{
public:
    void ToString()
    {
        cout << "I'm player" << endl;
    }
};

class Npc : public Character
{
public:
    void ToString()
    {
        cout << "I'm npc" << endl;
    }
};

int main(void) {
    Character* character1 = new Player();
    Character* character2 = new Npc();
    character1->ToString();
    character2->ToString();
    cin.get();
    return 0;
}

我们期望的输出:

I'm player
I'm npc

但实际输出的却是

I'm character
I'm character

百度了一下了解到,如果要想实现动态多态则必须使用虚函数virtual关键字

于是代码修改如下

#include"stdafx.h"
#include<iostream>
#include<string>
using namespace std;

class Character
{
public:
    virtual void ToString()
    {
        cout << "I'm character" << endl;
    }
};

class Player : public Character
{
public:
    virtual void ToString() override
    {
        cout << "I'm player" << endl;
    }
};

class Npc : public Character
{
public:
    virtual void ToString() override
    {
        cout << "I'm npc" << endl;
    }
};

int main(void) {
    Character* character1 = new Player();
    Character* character2 = new Npc();
    character1->ToString();
    character2->ToString();
    cin.get();
    return 0;
}

这样就可以得到我们预期的结果了

I'm player
I'm npc

 注意,上面代码中红色字体的virutal 和 override关键字不是必须的

 其中virtual不是必须的原因在于编译器默认子类有virtual关键字;

 override可以不加是因为:c++在c++11标准之前,没有类似于Java的@override检查机制,很容易子类在重载的时候写错方法签名,override应用而生,就是表明该方法是父类需方法的重载方法,编译器会强制检查方法签名是否一致

2018/8/12 更新

并非实现动态多态则必须使用虚函数virtual关键字,而是在引用类型为指针或者引用时必须如此,如果是普通对象不存在这种问题,伪代码如下:

AObject aObject;

BObject bObject;

aObject = bObject ,然后调用aObject.method则不需要virtual关键字也能实现多态

AObject* aObject;

BObject* bObject;

aObject = bObject ,然后调用aObject->method则必须要virtual关键字才能实现多态

 2018/8/17

1.virutal关键字在哪里加

如果声明和实现分离,vitual关键字只能出现在声明处,否则编译时会报错“... virtual 说明符在函数定义上非法”

如果声明和实现一体,vitual关键字可以出现在定义处,毕竟没有其他地方可加了

2.为什么析构函数应当被声明为虚函数

假设B为A的子类,且B增加了一个char*成员指向new分配的内存

A* a = new B();

delete a;

如果析构函数不是虚函数,这是将释放a的内存,此时没有指针再指向B,B中的char*成员也再没有机会得到释放

2018/8/18 0404

1.什么是纯虚函数?

一般的虚函数,形如 virutal string getName();

结尾加上 =0 就成了纯虚函数: virtual string getName() = 0;

2.为什么需要纯虚函数

比如设计椭圆类和正圆类,虽然正圆貌似应该继承椭圆,但考虑到细节的时候就会发现不合适,应为椭圆有许多正圆不具备的属性,因此应该增加一个抽象类,让椭圆和正圆都继承它,在这个类里,有一些方法是基本的且可以共用的,例如move(),但是又不需要在抽象基类中实现这个方法,这时候就应该将其定义为纯虚函数。

需要注意:

即使声明为纯虚方法,定义中仍然可以实现它;

含有纯虚方法的类无法被实例化;