c++ 多重繼承,an ambiguous base of

問題:html

  1. 問題

在寫代碼時,碰到了一個問題。有一個類多重繼承。該類沒法用基類指針去指代它。引發的問題。ios

代碼實例以下c++

#include <iostream>

using namespace std;

class Top
{
    public:
    Top(){}
	virtual ~Top()
    {}
	virtual void f()
	{
		cout<<"Top::f"<<endl;
	}

	virtual void g()
	{
		cout<<"Top::g()"<<endl;
	}
        int nData;
};

class Left: public Top
{
    public:
    Left(){

    }
    virtual ~Left()
    {

    }
	virtual void f()
	{
		cout<<"Left::f"<<endl;
	}

	virtual void g()
	{
		cout<<"Left::g()"<<endl;
	}
};

//int main()
//{
 //   //Left* t = new Left();
//    Top* t = new Left();
//    t->Top::f();
//}

class Right: public Top
{
    public:
    Right();
    ~Right();
	virtual void f()
	{
		cout<<"Right::f"<<endl;
	}

	virtual void g()
	{
		cout<<"Right::g()"<<endl;
	}
};

class Bottom: public Left, public Right
{
    public:
        Bottom();
        ~Bottom();
        virtual void f()
        {
            cout<<"Bottom::f"<<endl;
        }

        virtual void g()
        {
            cout<<"Bottom::g"<<endl;
        }
};

int main(){
    Top* t = new Bottom();
    return 0;
}

在個人ubuntu上。編譯時碰到的問題。ubuntu

multiple_inheritance.cpp:83:25: error: ‘Top’ is an ambiguous base of ‘Bottom’
     Top* t = new Bottom();

由這個問題,我去搜索資料。bash

  • 瞭解了什麼

瞭解了c++ 在實現繼承體系中的一些細節。ide

1.什麼是虛函數表。函數

2.多重繼承的二義性解決方法。虛繼承。spa

虛函數表

A virtual method table (VMT), virtual function table, virtual call table, dispath table (分發表), vtable, or vftable is a mechanism used in a programming language to support dynamic dispatch(動態分發) (or run-time method binding) (運行時綁定即動態綁定)..net

詳細內容能夠查看下面的查看資料。裏面講的挺詳細的。指針

個人理解。

由於在繼承的時候,若是沒有使用虛函數,即關鍵字virtual修飾函數。則用父類指針調用接口方法,則調用的是父類的方法。這是由於在類的虛函數表中(每一個類都會有虛函數表,用於動態綁定),該指針指向的位置函數就是父類的方法。(函數其實就是一個二進制地址)。若是用了virtual修飾函數,則這時候用父類指針指向的接口方法,則是子類的方法。

set print object on//顯示對象虛函數表
set print vtbl on//顯示虛函數表//做用在個人機器上好像是同樣的。

在上面的程序中,主函數是以下所示。

int main(){
    Top* pt = new Left();
    Left *pl = new Left();
    Left l;
    Fun pFun = NULL;
    pt->f();
    pt->Top::f();
    pFun();
    return 0;
}
(gdb) p *pt
$23 = (Left) {<Top> = {_vptr.Top = 0x400e30 <vtable for Left+16>, nData = 0}, <No data fields>}
(gdb) p *pl
$24 = (Left) {<Top> = {_vptr.Top = 0x400e30 <vtable for Left+16>, nData = 0}, <No data fields>}
(gdb) p l
$25 = (Left) {<Top> = {_vptr.Top = 0x400e30 <vtable for Left+16>, nData = 4196784}, <No data fields>}

打印p和pl和l所指向的內存。記得先打開顯示對象的內容。

發現指針先指向的內容是對象的數據。

存放的內容是先存儲虛地址表,而後存放數據段。

//順着去打印gdb指向的虛函數表發現以下。
(gdb) p /a *(void**) 0x400e30@10//@10指向的內容是指打印10個。
$39 = {0x400ca6 <Left::~Left()>, 0x400ce0 <Left::~Left()>, 0x400d06 <Left::f()>, 0x400d30 <Left::g()>, 0x0, 0x0, 0x0, 0x400ec0 <_ZTI3Top>, 
  0x400bd8 <Top::~Top()>, 0x400c06 <Top::~Top()>}

能夠發現,虛指針表指向的內容實際上是函數入口。

而全部的入口函數都被換成了left的。咱們如今把全部的virtual關鍵字去掉,看一下內存打印出來的函數入口是什麼樣子的。(這邊有點奇怪,我gdb打印的pt和pl的地址竟然會是同樣的。)

(gdb) x /32a (void**) 0x400c00
0x400c00 <Top::~Top()+14>:	0xffbae8c78948f845	0x8948f8458b48ffff
0x400c10 <Top::~Top()+30>:	0xc3c9fffffceae8c7	0x10ec8348e5894855
0x400c20 <Top::f()+8>:	0x400d84bef87d8948	0x1de800602100bf00
0x400c30 <Top::f()+24>:	0x400970befffffd	0xfffffd20e8c78948
0x400c40 <Top::f()+40>:	0x8348e5894855c3c9	0x8b48f87d894810ec
0x400c50 <Left::Left()+14>:	0xff54e8c78948f845	0xc748f8458b48ffff
0x400c60 <Left::Left()+30>:	0x90c3c900400db000	0x10ec8348e5894855
0x400c70 <Left::~Left()+8>:	0xf8458b48f87d8948	0x4800400db000c748
0x400c80 <Left::~Left()+24>:	0x39e8c78948f8458b	0xb8ffffff
0x400c90 <Left::~Left()+40>:	0xf8458b480c74c085	0xfffffc60e8c78948
0x400ca0 <Left::~Left()+56>:	0x8348e5894855c3c9	0x8b48f87d894810ec
0x400cb0 <Left::~Left()+14>:	0xffaee8c78948f845	0x8948f8458b48ffff
0x400cc0 <Left::~Left()+30>:	0xc3c9fffffc3ae8c7	0x10ec8348e5894855
0x400cd0 <Left::f()+8>:	0x400d8bbef87d8948	0x6de800602100bf00
0x400ce0 <Left::f()+24>:	0x400970befffffc	0xfffffc70e8c78948

主要是想說明,在沒有用虛函數的時候,內存存放的地址內容是先Top的全部方法,接着纔是top的方法。

2.接下來說一下虛繼承

接着上面的實例

若是我想用基類做爲指針指向其派生類Bottom。則須要在Left和right繼承父類的時候實用virtual。

這樣子編譯的時候就能夠經過了。

查看資料:

c++的多重繼承要慎用: https://www.cnblogs.com/bourneli/archive/2011/12/28/2305264.html

C++虛函數表解析: http://blog.csdn.net/haoel/article/details/1948051

wiki上面的內容:https://en.wikipedia.org/wiki/Virtual_inheritance

RTTI、虛函數和虛基類的實現方式、開銷分析及使用指導http://www.baiy.cn/doc/cpp/inside_rtti.htm

相關文章
相關標籤/搜索