繁体   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