实例一:
#include<iostream>
using namespace std;
class A
{
public:
virtual void foo()
{
cout<<"A::foo() is called"<<endl;
}
};
class B:public A
{
public:
void foo()
{
cout<<"B::foo() is called"<<endl;
}
};
int main(void)
{
A *a = new B();
a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
return 0;
}
输出:
B::foo() is called
实例二:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void f(float x)
{
cout<<"Base::f(float)"<< x <<endl;
}
virtual void k(float x)
{
cout<<"Base::k(float)"<< x <<endl;
}
void g(float x)
{
cout<<"Base::g(float)"<< x <<endl;
}
void h(float x)
{
cout<<"Base::h(float)"<< x <<endl;
}
};
class Derived : public Base
{
public:
virtual void f(float x)
{
cout<<"Derived::f(float)"<< x <<endl;
}
void k(float x)
{
cout<<"Derived::k(float)"<< x <<endl;
}
void g(float x)
{
cout<<"Derived::g(float)"<< x <<endl;
}
virtual void h(float x)
{
cout<<"Derived::h(float)"<< x <<endl;
}
};
int main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
pb->f(3.14f); // 输出:Derived::f(float) 3.14
pd->f(3.14f); // 输出:Derived::f(float) 3.14
pb->k(3.14f);
pd->k(3.14f);
pb->g(3.14f); // 输出:Base::g(float) 3.14
pd->g(3.14f); // 输出:Derived::g(int) 3.14
pb->h(3.14f);
pd->h(3.14f);
return 0;
}
输出:
Derived::f(float)3.14
Derived::f(float)3.14
Derived::k(float)3.14
Derived::k(float)3.14
Base::g(float)3.14
Derived::g(float)3.14
Base::h(float)3.14
Derived::h(float)3.14
分析 上述代码创建了Derived对象d,将Base类型指针pb和Derived类型指针pd指向d,可知pb和pd的编译时刻的类型分别是Base和Derivevd,而运行时刻类型均为Derived。看上述四个输出,pd的输出没有什么可说的,只是为了对比。重点是pb的f、g两个函数的输出,可见f为其运行时刻类型的输出结果,g为编译时刻的输出结果,而两者的区别即为f是虚函数。所以,可以得出结论,对于C++来说,虚函数完成了其动态多态的实现。
实例三:(OC多态实现)
#import <Foundation/Foundation.h>
@interface Base: NSObject
@end
@implementation Base
- (void)f {
NSLog(@"Base f");
}
@end
@interface Derived: Base
@end
@implementation Derived
- (void)f {
NSLog(@"Derived f");
}
@end
int main(int argc, char *argv[]) {
Derived *d = [[Derived alloc] init];
Base *pb = d;
Derived *pd = d;
[pb f]; // 输出:Derived f
[pd f]; // 输出:Derived f
return 0;
}
分析 和C++类似,上述代码创建了Derived对象d,将Base类型指针pb和Derived类型指针pd指向d,可知pb和pd的编译时刻的类型分别是Base和Derived,而运行时刻类型均为Derived。从两个输出来看,可以发现,OC并没有使用虚函数,也没有虚函数的概念,但是OC自动完成了动态多态的实现。
随记: 重写是子类的方法覆盖父类的方法,要求方法名和参数都相同。 重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数。
定义一个函数为虚函数,不代表函数为不被实现的函数。 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。 定义一个函数为纯虚函数,才代表函数没有被实现。 定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。