C ++多重继承和vtables [英] C++ multiple inheritance and vtables
问题描述
因此,回到基础知识,我想把头放在vtables之类的东西上.在下面的示例中,如果我想将B*
传递给某个函数,该函数如何知道调用C
对象的vtable中的方法,而不是调用A
的vtable中的方法? ?是否有两个单独的VTable传递给该对象?接口指针真的只是vtable(因为接口,IIRC不能包含属性声明)吗?
我要说的是,直到我实际尝试这段代码之前,我一直以为您不能一次继承多个接口/类(并且所有接口必须继承).可以说是线性的),以便将vtable建立在其自身上.
如果我对vtables是如何工作的想法 是正确的(我现在知道不是),那么传递B*
并调用B::OutB()
将会调用A:OutA()
(这是显然不是这样.
有人可以照亮吗?
// Includes
#include <windows.h>
#include <iostream>
interface A
{
public:
virtual void OutA() = 0;
};
interface B
{
public:
virtual void OutB() = 0;
};
class C : public A, public B
{
public:
void OutA();
void OutB();
};
void C::OutA()
{
printf("Out A\n");
}
void C::OutB()
{
printf("Out B\n");
}
int main()
{
C obj;
obj.OutA();
obj.OutB();
A* ap = (A*)&obj;
B* bp = (B*)&obj;
ap->OutA();
bp->OutB();
system("pause");
// Return
return 0;
}
输出(按预期):
Out A
Out B
Out A
Out B
我不知道interface
是什么的原因,因为:
-
interface
不是 一个C ++关键字; - 在C ++语义中没有接口"的概念;
- 不同的C ++习惯用法或模式可以将word接口用于不同的特定目的;
- 其他语言使用接口"来描述完全不同的实体(在Java中,这就像是一种特殊的有限基类,在O'Caml中,它用在C ++中可能使用模板概念的地方).
但是,如果您正在编写C ++并且A
和B
是类,则C
将包含两个子对象:A
和B
,并且这些子对象中的每一个都有其自己的vtable指针. /p>
将C ++编译为C时,我们可以:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
const int debug = 0;
void __pure_virtual_called() {
fputs ("pure virtual function called\n", stderr);
abort();
}
/* Translation of:
class A
{
public:
virtual void OutA() = 0;
};
*/
struct A;
typedef struct {
void (*ptr__OutA) (struct A *__this);
} vtable__A;
typedef struct A {
vtable__A *__vptr;
} A;
/* translation A::OutA()
* pure virtual function */
void A__OutA (A *__this) {
__pure_virtual_called();
}
vtable__A vtable__A__A = { .ptr__OutA = A__OutA };
void A__constructor (A *__this) {
if (debug)
printf ("A__constructor %p\n", (void*)__this);
/* dynamic type is initialised to A */
__this->__vptr = &vtable__A__A;
}
/* Translation of:
class B
{
public:
virtual void OutB() = 0;
};
*/
struct B;
typedef struct {
void (*ptr__OutB)(struct B *__this);
} vtable__B;
typedef struct B {
vtable__B *__vptr;
} B;
/* translation B::OutB()
* pure virtual function */
void B__OutB (B *__this) {
__pure_virtual_called();
}
vtable__B vtable__B__B = { .ptr__OutB = B__OutB };
void B__constructor (B *__this) {
if (debug)
printf ("B__constructor %p\n", (void*)__this);
/* dynamic type is initialised to B */
__this->__vptr = &vtable__B__B;
}
/* Translation of:
class C : public A, public B
{
public:
void OutA(); // overrides A::OutA()
void OutB(); // overrides B::OutB()
// note :
// no new virtual function
};
*/
/* no new virtual function
* so no specific vtable type! */
typedef struct {
/* no additional vptr, we already have 2! */
A base__A;
B base__B;
} C;
/******* upcasts
* translation of
* static_cast<C*> (p)
*/
/* translation of
* A *p;
* static_cast<C*> (p);
*/
C *static_cast__A__C (A *__ptr) {
/*
* base__A is first member of C
* so offsetof(C, base__A) == 0
* can skip the pointer adjustment
*/
return (C*)__ptr;
}
/* translation of
* B *p;
* static_cast<C*> (p);
*/
C *static_cast__B__C (B *__ptr) {
/* locate enclosing C object:
* __base__B is not first member
* need to adjust pointer
*/
return (C*)((char*)__ptr - offsetof(C, base__B));
}
/* translation of virtual functions of C
* overriding function declarations from A
*/
/* translation of C::OutA() */
/* C::OutA() called from C */
void C__OutA (C *__this) {
printf("Out A this=%p\n", (void*)__this);
}
/* C::OutA() called from A */
void C__A__OutA (A *__this) {
if (debug)
printf ("C__A__OutA %p\n", (void*)__this);
C__OutA (static_cast__A__C (__this));
}
vtable__A vtable__A__C = { .ptr__OutA = C__A__OutA };
/* translation of virtual functions of C
* overriding function declarations from B
*/
/* translation of C::OutB() */
/* C::OutB() called from C */
void C__OutB (C *__this) {
printf("Out B this=%p\n", (void*)__this);
}
/* C::OutB() called from B */
void C__B__OutB (B *__this) {
if (debug)
printf ("C__B__OutB %p\n", (void*)__this);
C__OutB (static_cast__B__C (__this));
}
vtable__B vtable__B__C = { .ptr__OutB = C__B__OutB };
void C__constructor (C *__this) {
if (debug)
printf ("C__constructor %p\n", (void*)__this);
/* construct subobjects */
A__constructor (&__this->base__A);
B__constructor (&__this->base__B);
/* adjust dynamic type of this to C */
__this->base__A.__vptr = &vtable__A__C;
__this->base__B.__vptr = &vtable__B__C;
}
/* calls to C virtual functions with a C*
*/
/* translation of
* C *p;
* p->OutA();
*
* is
* ((A*)p)->OutA();
*
* because C::OutA() is overrides A::OutA()
*/
void dyn__C__OutA (C *__this) {
A *base_ptr__A = &__this->base__A;
base_ptr__A->__vptr->ptr__OutA (base_ptr__A);
}
/* translation of
int main()
{
C obj;
obj.OutA();
obj.OutB();
A *ap = &obj;
B *bp = &obj;
C *cp = &obj;
ap->OutA();
bp->OutB();
cp->OutA();
// Return
return 0;
}
*
*/
int main () {
/* translation of:
C obj;
*/
C obj;
C__constructor (&obj);
/* translation of:
obj.OutA();
obj.OutB();
* obj is a locally declared object
* so dynamic type of obj is known as C
* can make direct call to C::OutA(), C::OutB()
*/
C__OutA (&obj);
C__OutB (&obj);
/* dumb (zero optimisation) translation of:
A *ap = &obj;
B *bp = &obj;
C *cp = &obj;
*/
A *ap = &obj.base__A;
B *bp = &obj.base__B;
C *cp = &obj;
/* translation of:
ap->OutA();
bp->OutB();
cp->OutA();
* dumb compiler = no optimisation
* so dynamic type of *ap, *bp, *cp is unknown
* so make "virtual" calls using vtable
*/
ap->__vptr->ptr__OutA(ap);
bp->__vptr->ptr__OutB(bp);
dyn__C__OutA (cp);
/* note: obj lifetime ends now
* C has a trivial destructor
* so no destructor call needed
*/
return 0;
}
输出:
Out A this=0xbfeee2ec
Out B this=0xbfeee2ec
Out A this=0xbfeee2ec
Out B this=0xbfeee2ec
Out A this=0xbfeee2ec
So going back to basics, I'm trying to wrap my head around vtables and whatnot. In the following example, if I were to, say, pass a B*
to some function, how does that function know to call the methods in the vtable of the C
object instead of the methods from the vtable of A
? Are there two, separate VTables that are passed to that object? Are interface pointers really just vtables (since interfaces, IIRC, cannot contain property declarations)?
What I'm trying to say is, up until I actually tried this code, I was under the assumption you couldn't inherit off of more than one interface/class at a time (and that all of the interfaces had to be linear, so to speak) so that the vtable built onto itself.
If my idea of how vtables worked was correct (which I now know it is not), then passing a B*
and called B::OutB()
would have called A:OutA()
instead (which is obviously not the case).
Can someone shed some light?
// Includes
#include <windows.h>
#include <iostream>
interface A
{
public:
virtual void OutA() = 0;
};
interface B
{
public:
virtual void OutB() = 0;
};
class C : public A, public B
{
public:
void OutA();
void OutB();
};
void C::OutA()
{
printf("Out A\n");
}
void C::OutB()
{
printf("Out B\n");
}
int main()
{
C obj;
obj.OutA();
obj.OutB();
A* ap = (A*)&obj;
B* bp = (B*)&obj;
ap->OutA();
bp->OutB();
system("pause");
// Return
return 0;
}
outputs (as expected):
Out A
Out B
Out A
Out B
I have no idea what an interface
is, because:
interface
is not a C++ keyword;- there is no concept of an "interface" in C++ semantics;
- different C++ idioms or patterns can use the word interface for different specific purposes;
- other languages use "interface" to describe completely different entities (in Java it's like sort of special limited base class, in O'Caml it's used where in C++ you might use a template concept).
But if you were writing C++ and A
and B
were classes, then C
would contain two subobjects: A
and B
, and each of these subobject would have its own vtable pointer.
When compiling C++ to C, we could have:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
const int debug = 0;
void __pure_virtual_called() {
fputs ("pure virtual function called\n", stderr);
abort();
}
/* Translation of:
class A
{
public:
virtual void OutA() = 0;
};
*/
struct A;
typedef struct {
void (*ptr__OutA) (struct A *__this);
} vtable__A;
typedef struct A {
vtable__A *__vptr;
} A;
/* translation A::OutA()
* pure virtual function */
void A__OutA (A *__this) {
__pure_virtual_called();
}
vtable__A vtable__A__A = { .ptr__OutA = A__OutA };
void A__constructor (A *__this) {
if (debug)
printf ("A__constructor %p\n", (void*)__this);
/* dynamic type is initialised to A */
__this->__vptr = &vtable__A__A;
}
/* Translation of:
class B
{
public:
virtual void OutB() = 0;
};
*/
struct B;
typedef struct {
void (*ptr__OutB)(struct B *__this);
} vtable__B;
typedef struct B {
vtable__B *__vptr;
} B;
/* translation B::OutB()
* pure virtual function */
void B__OutB (B *__this) {
__pure_virtual_called();
}
vtable__B vtable__B__B = { .ptr__OutB = B__OutB };
void B__constructor (B *__this) {
if (debug)
printf ("B__constructor %p\n", (void*)__this);
/* dynamic type is initialised to B */
__this->__vptr = &vtable__B__B;
}
/* Translation of:
class C : public A, public B
{
public:
void OutA(); // overrides A::OutA()
void OutB(); // overrides B::OutB()
// note :
// no new virtual function
};
*/
/* no new virtual function
* so no specific vtable type! */
typedef struct {
/* no additional vptr, we already have 2! */
A base__A;
B base__B;
} C;
/******* upcasts
* translation of
* static_cast<C*> (p)
*/
/* translation of
* A *p;
* static_cast<C*> (p);
*/
C *static_cast__A__C (A *__ptr) {
/*
* base__A is first member of C
* so offsetof(C, base__A) == 0
* can skip the pointer adjustment
*/
return (C*)__ptr;
}
/* translation of
* B *p;
* static_cast<C*> (p);
*/
C *static_cast__B__C (B *__ptr) {
/* locate enclosing C object:
* __base__B is not first member
* need to adjust pointer
*/
return (C*)((char*)__ptr - offsetof(C, base__B));
}
/* translation of virtual functions of C
* overriding function declarations from A
*/
/* translation of C::OutA() */
/* C::OutA() called from C */
void C__OutA (C *__this) {
printf("Out A this=%p\n", (void*)__this);
}
/* C::OutA() called from A */
void C__A__OutA (A *__this) {
if (debug)
printf ("C__A__OutA %p\n", (void*)__this);
C__OutA (static_cast__A__C (__this));
}
vtable__A vtable__A__C = { .ptr__OutA = C__A__OutA };
/* translation of virtual functions of C
* overriding function declarations from B
*/
/* translation of C::OutB() */
/* C::OutB() called from C */
void C__OutB (C *__this) {
printf("Out B this=%p\n", (void*)__this);
}
/* C::OutB() called from B */
void C__B__OutB (B *__this) {
if (debug)
printf ("C__B__OutB %p\n", (void*)__this);
C__OutB (static_cast__B__C (__this));
}
vtable__B vtable__B__C = { .ptr__OutB = C__B__OutB };
void C__constructor (C *__this) {
if (debug)
printf ("C__constructor %p\n", (void*)__this);
/* construct subobjects */
A__constructor (&__this->base__A);
B__constructor (&__this->base__B);
/* adjust dynamic type of this to C */
__this->base__A.__vptr = &vtable__A__C;
__this->base__B.__vptr = &vtable__B__C;
}
/* calls to C virtual functions with a C*
*/
/* translation of
* C *p;
* p->OutA();
*
* is
* ((A*)p)->OutA();
*
* because C::OutA() is overrides A::OutA()
*/
void dyn__C__OutA (C *__this) {
A *base_ptr__A = &__this->base__A;
base_ptr__A->__vptr->ptr__OutA (base_ptr__A);
}
/* translation of
int main()
{
C obj;
obj.OutA();
obj.OutB();
A *ap = &obj;
B *bp = &obj;
C *cp = &obj;
ap->OutA();
bp->OutB();
cp->OutA();
// Return
return 0;
}
*
*/
int main () {
/* translation of:
C obj;
*/
C obj;
C__constructor (&obj);
/* translation of:
obj.OutA();
obj.OutB();
* obj is a locally declared object
* so dynamic type of obj is known as C
* can make direct call to C::OutA(), C::OutB()
*/
C__OutA (&obj);
C__OutB (&obj);
/* dumb (zero optimisation) translation of:
A *ap = &obj;
B *bp = &obj;
C *cp = &obj;
*/
A *ap = &obj.base__A;
B *bp = &obj.base__B;
C *cp = &obj;
/* translation of:
ap->OutA();
bp->OutB();
cp->OutA();
* dumb compiler = no optimisation
* so dynamic type of *ap, *bp, *cp is unknown
* so make "virtual" calls using vtable
*/
ap->__vptr->ptr__OutA(ap);
bp->__vptr->ptr__OutB(bp);
dyn__C__OutA (cp);
/* note: obj lifetime ends now
* C has a trivial destructor
* so no destructor call needed
*/
return 0;
}
Output:
Out A this=0xbfeee2ec
Out B this=0xbfeee2ec
Out A this=0xbfeee2ec
Out B this=0xbfeee2ec
Out A this=0xbfeee2ec
这篇关于C ++多重继承和vtables的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!