C++对象模型(中)多继承

本文详细解析了C++中多继承与菱形继承的对象模型及虚函数表布局,包括简单多继承、菱形继承及菱形虚拟继承的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

上一篇介绍了单继承体系中的对象模型:请戳:点击打开链接

 

多继承体系下的对象模型

 

一、简单多继承

例如下面代码:

class B
{
public:
	virtual void func_1()//虚函数
	{
		cout << "B ::func_1()\n";
	}
	virtual void func_2()//虚函数
	{
		cout << "B ::func_2()\n";
	}
//protected:
	int _b;
};


class C
{
public:
	virtual void func_1()//虚函数
	{
		cout << "C ::func_1()\n";
	}
	virtual void func_3()//虚函数
	{
		cout << "C ::func_3()\n";
	}
//protected:
	int _c;
};


class D :public B ,public C
{
public:
	virtual void func_1()//重写了父类中的虚函数
	{
		cout << "D ::func_1()\n";
	}
	virtual void func_4()//Derive 类自己的虚函数
	{
		cout << "D ::func_4()\n";
	}
	void func_5()//普通成员函数
	{
		cout << "D ::func_5()\n";
	}
//protected:
	int _d;
};


typedef void(*VFUNC)(void);

void PrintVTable(int *table,const string &str)
{
	int i = 0;
	cout << str << endl;
	printf("table :0x%p\n", table);//打印虚表指针
	for (i = 0; table[i] != NULL; ++i)
	{
		printf("table[%d]:0x%p->", i, table[i]);//将虚表中的每一个虚函数地址打印出来
		VFUNC f = (VFUNC)table[i];//将虚函数的地址转换为函数指针
		f();//调用虚函数
	}
}


int main()
{
	D d1;
	d1._b = 1;
	d1._c = 2;
	d1._d = 3;
	PrintVTable((int *)(*((int *)(&d1))),"第一张虚表");
	PrintVTable((int *)(*((int *)((char *)&d1+sizeof(B)))),"第二张虚表");
	system("pause");
	return 0;
}

 

 

因为D继承了两个父类,所以D类中是有两张虚表,而且D对象独有的虚函数也放在第一张虚表中,这里因为D对象先继承了B对象,所以从对象模型来看,B对象在D对象的上面部分,并且B的虚表中还要存放D对象独有的虚函数,当D对func_1()进行了重写,B和C虚表中的func_1()都会被覆盖。

 

二、多继承中菱形继承

class A
{
public:
    virtual void func_1()//虚函数
    {
        cout << "A ::func_1()\n";
    }
    virtual void func_2()//独有的虚函数
    {
        cout << "A ::func_2()\n";
    }
//protected:
    int _a;
};


class B :public A
{
public:
    virtual void func_1()//虚函数
    {
        cout << "B ::func_1()\n";
    }
    virtual void func_3()//虚函数
    {
        cout << "B ::func_3()\n";
    }
    virtual void func_4()//虚函数
    {
        cout << "B ::func_4()\n";
    }
    //protected:
    int _b;
};


class C :public A
{
public:
    virtual void func_1()//虚函数
    {
        cout << "C ::func_1()\n";
    }

    virtual void func_5()//虚函数
    {
        cout << "C ::func_5()\n";
    }

    virtual void func_6()//虚函数
    {
        cout << "C ::func_6()\n";
    }
//protected:
    int _c;
};


class D :public B ,public C
{
public:
    virtual void func_1()//重写了B和C的虚函数
    {
        cout << "D ::func_1()\n";
    }
    virtual void func_3()//重写了B的虚函数
    {
        cout << "D ::func_3()\n";
    }

    virtual void func_5()//重写了C的虚函数
    {
        cout << "D ::func_5()\n";
    }
    virtual void func_7()//独有的虚函数
    {
        cout << "D ::func_7()\n";
    }
//protected:
    int _d;
};


typedef void(*VFUNC)(void);

void PrintVTable(int *table,const string &str)
{
    int i = 0;
    cout << str << endl;
    printf("table :0x%p\n", table);//打印虚表指针
    for (i = 0; table[i] != NULL; ++i)
    {
        printf("table[%d]:0x%p->", i, table[i]);
        //将虚表中的每一个虚函数地址打印出来
        VFUNC f = (VFUNC)table[i];
        //将虚函数的地址转换为函数指针
        f();//调用虚函数
    }
}


int main()
{
    D d1;
    d1.B::_a = 1;
    d1.C::_a = 2;
    d1._b = 3;
    d1._c = 4;
    d1._d = 5;
    PrintVTable((int *)(*((int *)(&d1))),"第一张虚表");
    PrintVTable((int *)(*((int *)((char *)&d1+sizeof(B)))),"第二张表");
    system("pause");
    return 0;
}

因为是菱形继承,这里的B和C对象中都会分别有一个A对象,当然D中自己的虚函数也是放在第一个继承的父类的虚表中的,这里就是放在B对象中的A对象中的虚表中。

如果已经忘了菱形继承的请戳:点击打开链接

三、菱形虚拟继承

class A
{
public:
	virtual void func_1()//虚函数
	{
		cout << "A ::func_1()\n";
	}
	virtual void func_2()//独有的虚函数
	{
		cout << "A ::func_2()\n";
	}
	//protected:
	int _a;
};
class B :virtual public A
{
public:
	virtual void func_1()//虚函数
	{
		cout << "B ::func_1()\n";
	}
	virtual void func_3()//虚函数
	{
		cout << "B ::func_3()\n";
	}
	virtual void func_4()//虚函数
	{
		cout << "B ::func_4()\n";
	}

	//protected:
	int _b;
};
class C :virtual public A
{
public:
	virtual void func_1()//虚函数
	{
		cout << "C ::func_1()\n";
	}
	virtual void func_5()//虚函数
	{
		cout << "C ::func_5()\n";
	}
	virtual void func_6()//虚函数
	{
		cout << "C ::func_6()\n";
	}
	//protected:
	int _c;
};
class D :public B, public C
{
public:
	virtual void func_1()//重写了B和C的虚函数
	{
		cout << "D ::func_1()\n";
	}
	virtual void func_3()//重写了B的虚函数
	{
		cout << "D ::func_3()\n";
	}
	virtual void func_5()//重写了C的虚函数
	{
		cout << "D ::func_5()\n";
	}

	virtual void func_7()//独有的虚函数
	{
		cout << "D ::func_7()\n";
	}
	//protected:
	int _d;
};

typedef void(*VFUNC)(void);

void PrintVTable(int *table, const string &str)
{
	int i = 0;
	cout << str << endl;
	printf("table :0x%p\n", table);//打印虚表指针
	for (i = 0; table[i] != NULL; ++i)
	{
		printf("table[%d]:0x%p->", i, table[i]);//将虚表中的每一个虚函数地址打印出来
		VFUNC f = (VFUNC)table[i];//将虚函数的地址转换为函数指针
		f();//调用虚函数
	}
}
int main()
{
	D d1;
	d1._a = 1;
	d1._b = 2;
	d1._c = 3;
	d1._d = 4;
	PrintVTable((int *)(*((int *)(&d1))), "第一张虚表");
	PrintVTable((int *)(*((int *)((char *)&d1 + sizeof(B)-sizeof(A)))), "第二张虚表");
	PrintVTable((int *)(*((int *)((char *)&d1 + sizeof(B)-sizeof(A)+sizeof(C) - sizeof(A)+sizeof(D)-sizeof(B)-sizeof(C)+sizeof(A)))), "第三张虚表");
	system("pause");
	return 0;
}

 


从上面的模型来看,D类中有三张虚表,一张是A的,里面放的是B和C继承了A了虚函数,一张是放B自己的虚函数和D中独有的虚函数(因为D是先继承了B),一张是放C自己的虚函数。

当然如果B没有自己的虚函数,并且D类也没有自己独有的虚函数,那么这里就不会为B开辟块空间放B的虚函数表,同理,如果C类中没有自己独有的虚函数,那么也就不会为C开辟一块空间放C的虚函数表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值