1. 虚继承简单的说就是如果有两个类都继承了同一个基类(A),那么,如果有第三个类又继承了这两个类,第三个类就会出现有 两个基类(A)的情况,虚继承就能避免这种情况。
从实现代码来看:
普通继承:
/**
普通继承(没有使用虚基类)
*/
// 基类A
class A
{
public:
int dataA;
};
class B : public A
{
public:
int dataB;
};
class C : public A
{
public:
int dataC;
};
class D : public B, public C
{
public:
int dataD;
};
虚继承:
/**
虚继承(虚基类)
*/
#include <iostream>
// 基类A
class A
{
public:
int dataA;
};
class B : virtual public A
{
public:
int dataB;
};
class C : virtual public A
{
public:
int dataC;
};
class D : public B, public C
{
public:
int dataD;
};
从实现原理来说,就是虚继承的话 派生类对象 会产生一个 虚表指针(就是一个指针),指向一个虚表 ,对象D 继承了B、C
也会同时继承两个虚表指针,两个虚表指针指向的虚表上有记录 B、C 都有的基类在对象D ,内存中的一个偏移距离,从而
实现了D中指挥有一个A 。
建议大家还可以去看看这个大神的博客 http://blog.youkuaiyun.com/xiejingfa/article/details/48028491
2. 虚函数
先说一下C++ 有动态绑定和静态绑定的区别。 静态绑定是指编译器在编译的时候就完成了绑定,比如函数重载,编译器会根据传递给函数的参数就可以判定使用哪一个重载函数。
而动态绑定,就是靠虚函数的机制来实现的,并实现了多态机制,多态是面向对象程序设计语言的基本特征之一。在C++中,多态就是利用基类指针指向子类(注意:只能子类转换成基类)实例,然后通过基类指针调用子类(虚)函数,从而实现一个接口,多种形态的效果。(可能有点绕,多读几遍就好了)
或者使用基类的引用来调用虚函数也可实现
下面 用一个简单的例子看看效果啦:
class Base1
{
public:
virtual void func1() { cout << "Base1::func1()" << endl; }
void func2() { cout << "Base1::func2()" << endl; }
};
class Base2 : public Base1
{
void func1() { cout << "Base2::func1()" << endl; }
};
int main()
{
cout << "virtual function testing:" << endl;
Base2 b;
Base1 *ptr = &b;
ptr->func1();
ptr->func2();
}
输出结果: 自己理解理解,注意我上面讲的动态绑定。
下面讲一下具体实现原理:
每一个带虚函数的类对象在内存地址的开头都会有一个虚表指针 指向了一个虚表,表上记录了对象内 虚函数 的地址。
每一个继承了 这个带虚函数 的类 实例化的对象(并且重写了,基类中的虚函数),也会有一个虚表指针,并且这虚表指针之指向的虚表上记录的是 是当前类内的 (已经重写的)那个函数的地址。
这样的话,当用基类指针指向子类实例时就会用虚表上记录的函数来调用了,也就是会调用基类重写后的。