一段代码
#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(),但是又不需要在抽象基类中实现这个方法,这时候就应该将其定义为纯虚函数。
需要注意:
即使声明为纯虚方法,定义中仍然可以实现它;
含有纯虚方法的类无法被实例化;