此篇博客主要介绍菱形虚拟继承和虚函数的混合情况下的模型分析。
一.首先介绍一下虚函数的实质内容
1.没有虚继承的虚函数
class A
{
public:
int a;
virtual void fun1()
{
cout << "A::fun1 " << endl;
}
};
class B :public A
{
public:
int b;
virtual void fun1()//函数重写
{
cout << "B::fun1 " << endl;
}
virtual void fun2()
{
cout << "B::fun2" << endl;
}
};
int main()
{
B b;//创建一个B的对象
A a;
b.b = 20;
a.a = 10;
b.a = 30;
system("pause");
return 0;
}
首先我们来看对象a的虚函数机制
接下里我们对B对象虚表里面的 函数进行验证,对象自己验证
typedef void(*fun)();//这里定义fun为函数指针类型
fun *p = (fun *)*(int*)(&b);
(*p)();//打印B::fun1
p++;//指向B::fun2
(*p)();//打印B::fun2
2.有虚继承的虚函数
首先看这个类的大小:
class A
{
public:
int a;
virtual void fun1()
{
cout << "A::fun1 "<< endl;
}
};
class B :virtual public A
{
public:
int b;
virtual void fun1()//函数重写
{
cout << "B::fun1 " << endl;
}
virtual void fun2()
{
cout << "B::fun2" << endl;
}
};
int main()
{
B b;
A a;
b.b=20;
a.a=10;
sizeof(B);
system("pause");
return 0;
}
刚才无虚继承的类大小是12怎么加了个vurtual虚继承以后就变成了20呢?一下多了八个字节,接下来我们详细分析。
接下来打印验证:
typedef void(*fun)();//这里定义fun为函数指针类型
fun *p = (fun *)*(int*)(&b);
(*p)();
p += 4;;
(*p)();
3.菱形继承➕虚函数
首先给出基本代码:
class A
{
public:
int _a;
virtual void fun1()
{
cout << "A::fun1" << endl;
}
virtual void fun2()
{
cout << "A::fun2" << endl;
}
};
class B1 : virtual public A
{
public:
int _b1;
virtual void fun1()
{
cout << "B1::fun1" << endl;
}
virtual void fun3()
{
cout << "B1::fun3" << endl;
}
};
class B2 :virtual public A
{
public:
int _b2;
virtual void fun1()
{
cout << "B2::fun1" << endl;
}
virtual void fun4()
{
cout << "B2::fun4" << endl;
}
};
class C :public B1,public B2
{
public:
int _c;
virtual void fun1()
{
cout << "C::fun1" << endl;
}
virtual void fun3()
{
cout << "C::fun3" << endl;
}
virtual void fun4()
{
cout << "C::fun4" << endl;
}
virtual void fun5()
{
cout << "C::fun5" << endl;
}
};
int main()
{
cout <<"A:"<< sizeof(A) << endl;
cout << "B1:"<<sizeof(B1) << endl;
cout << "B2:"<<sizeof(B2) << endl;
cout << "C:"<<sizeof(C) << endl;
A a;
B1 b1;
B2 b2;
C c;
a._a = 10;
b1._a = 10;
b1._b1 = 20;
b2._b2 = 30;
b2._a = 10;
c._c = 40;
c._a = 10;
c._b1 = 20;
c._b2 = 30;
system("pause");
return 0;
}
先来看看每个对象的大小然后我在逐个对象分析其模型
注意这里的B是B1,图上写的是B
接下来打印验证
typedef void(*fun)();//这里定义fun为函数指针类型
fun *p = (fun *)*(int*)(&c);
(*p)();//C::fun3
(*(p + 1))();//C::fun5
(*(p + 3))();//C::fun4
(*(p + 5))();//C::fun1
(*(p + 6))();//A::fun2
总结:1.无虚继承时在虚函数中,派生类中的虚函数非基类重写,则将其放置在继承来的虚函数表后面,不重新开辟虚函数表,并且将派生类中重写的虚函数替换基类中的虚函数
2.有虚继承虚函数时,派生类中的虚函数如果不是基类的重写的话,新开辟一个虚函数表将未重写虚函数放进去,将继承来的虚函数表放在其后面,并且将重写的替换
3.菱形继承+虚函数时,最重要的一点就是在,最低层的派生类中(上述例子就是C),只有一份基类(A)的虚表,并且在其模型(C模型)的最下面。并且将其没有重写的虚函数放在第一个继承模型(B1)的虚函数表下面,而且将其重写的也要替换为自己的。