-
虚函数:在类的成员函数前加virtual关键,这时成员函数就是虚函数。这里需要注意的是必须是类的成员函数。
-
虚函数表:通过一块连续的内存来存储虚函数的地址。在对象的模型里存着。如下所示:
class Base
{
public:
virtual void Fun1()
{
cout << "Base::Fun1()" << endl;
}
virtual void Fun2()
{
cout << "Base::Fun2()" << endl;
}
public:
int _Base;
};
class Derive:public Base
{
public:
virtual void Fun1()
{
cout << "Derive::Fun()" << endl;
}
virtual void Fun3()
{
cout << "Derive::Fun3()" << endl;
}
virtual void Fun4()
{
cout << "Derive::Fun4()" << endl;
}
public:
int _Derive;
};
上述的图示(单继承):
菱形虚拟继承:(多继承)
下面通过一段简单的菱形继承的代码来分析:
//菱形虚拟继承博客演示
class A
{
public:
virtual void f1()
{
cout << "A::f1()" << endl;
}
virtual void f2()
{
cout << "A::f2()" << endl;
}
int _a;
};
class B :virtual public A
{
public:
virtual void f1()
{
cout << "B::f1()" << endl;
}
virtual void f3()
{
cout << "B::f3()" << endl;
}
int _b;
};
class C :virtual public A
{
public:
virtual void f1()
{
cout << "C::f1()" << endl;
}
virtual void f4()
{
cout << "C::f4()" << endl;
}
int _c;
};
class D :public B, public C
{
public:
virtual void f1()
{
cout << "D::f1()" << endl;
}
virtual void f5()
{
cout << "D::f5()" << endl;
}
int _d;
};
typedef void(*VfTables)() ; //函数指针
void printVfptr(int **VfTable)
{
printf("虚表的地址:%p \n",VfTable);
for (size_t i = 0; VfTable[i] != 0; ++i)
{
printf("VfTable[%d] :%p -> ",i,VfTable[i]);
VfTables func = (VfTables)VfTable[i];
func();
}
}
int main()
{
D d;
d._a = 1;
d._b = 2;
d._c = 3;
d._d = 4;
cout << "====================================" << endl;
printVfptr(((int**)(*(int**)&d)));
cout << "====================================" << endl;
printVfptr((int**)(*((int**)((char*)&d + sizeof(B)-sizeof(A)))));
cout << "====================================" << endl;
printVfptr((int**)(*(int**)((char*)&d + sizeof(D)-sizeof(A))));
cout << "====================================" << endl;
return 0;
}
图示分析:
- 多态:即多种形态。
触发多态的条件:1.父类的指针或引用调用虚函数
2.虚函数的重写(覆盖)
- 为什么多态非要是对象的指针或者引用呢?
- 否则就是值拷贝,不拷贝虚表
下面是代码实现多态:
class A
{
public:
virtual void Fun1()
{
cout << "A::Fun1" << endl;
}
void GetFun()
{
Fun1();
}
};
class B :public A
{
public:
virtual void Fun1()
{
cout << "B::Fun1" << endl;
}
};
int main()
{
A a;
B b;
A* pa = &a;
pa->GetFun();
pa = &b;
pa->GetFun();
}
这里就可以看出来的,pa是一个A*的类型,但是通过同一类型的指针,调了两个不同的函数,一个是父类的Fun1,一个是子类的Fun1。
重写,重载,隐藏的区别: