簡體   English   中英

虛擬類的多重繼承

[英]Multiple inheritance of virtual classes

假設我有以下代碼:

class a {
public:
    virtual void do_a() = 0;
}

class b {
public:
    virtual void do_b() = 0;
}

class c: public a, public b {
public:
    virtual void do_a() {};
    virtual void do_b() {};
}

a *foo = new c();
b *bar = new c();

foo->do_a()bar->do_b()工作? 這里的內存布局是什么?

a-> do_a()和b-> do_b()是否可以工作?

假設您的意思是foo->do_a()bar->do_b() ,因為ab不是object ,它們的類型為 yes。 他們會工作的。 你試過那樣嗎?

這里的內存布局是什么?

那主要是實現定義的。 幸運的是,除非您想編寫不可移植的代碼,否則您無需了解這一點。

他們為什么不呢? 內存布局通常如下所示:

+----------+
|  A part  |
+----------+
|  B part  |
+----------+
|  C part  |
+----------+

如果將foobar轉換為void*並顯示它們,則會獲得不同的地址,但是編譯器知道這一點,並且會在調用函數時安排this指針正確固定。

正如其他人所提到的,以下內容將毫無問題地起作用

foo->do_a();
bar->do_b();

但是,這些將無法編譯

bar->do_a();
foo->do_b();

由於barb*類型,因此不知道do_a foodo_b也是如此。 如果要進行這些函數調用,則必須向下轉換。

static_cast<c *>(foo)->do_b();
static_cast<c *>(bar)->do_a();

示例代碼中未顯示的另一個非常重要的事情是,在繼承並通過基類指針引用派生類時,基類必須具有一個虛擬析構函數 如果不是,則以下內容將產生未定義的行為。

a* foo = new c();
delete a;

解決方法很簡單

class a {
public:
    virtual void do_a() = 0;

    virtual ~a() {}
};

當然,也需要對b進行此更改。

foo->do_a();   // will work
bar->do_b();   // will work
bar->do_a();   // compile error (do_a() is not a member of B)
foo->do_b();   // compile error (do_b() is not a member of A)

// If you really know the types are correct:
C* c = static_cast<C*>(foo);

c->do_a();  // will work
c->do_b();  // will work

// If you don't know the types, you can try at runtime:
if(C* c = dynamic_cast<C*>(foo))
{
    c->do_a();  // will work
    c->do_b();  // will work
}

是的,當然可以。 機械學有點棘手。 該對象將具有兩個vtable,一個用於父類的vtable,另一個用於父類b的vtable。 指針將被調整,使其指向與指針類型相對應的對象子集,從而導致以下令人驚訝的結果:

c * baz = new c;
a * foo = baz;
b * bar = baz;
assert((void *)foo == (void *)bar); // assertion fails!

編譯器在分配時就知道類型,並且確切地知道如何調整指針。

當然,這完全取決於編譯器。 C ++標准中沒有任何內容表明它必須以這種方式工作。 只是它必須起作用。

a-> do_a()和b-> do_b()是否可以工作?

沒有。

foo->do_a()bar->do_b()工作?

是。 您的代碼是虛擬函數分派的典型示例。

你為什么不試試呢?

這里的內存布局是什么?

誰在乎?

(即,這是實現定義的,從您那里抽象出來的。您既不需要也不想知道。)

他們會工作的。 就內存而言,這取決於實現。 您已經在堆上創建了對象,並且對於大多數系統而言,值得注意的是堆上的對象向上增長(如果堆棧向下增長)。 因此, 可能會有:

Memory:

+foo+
-----
+bar+

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM