Полиморфное наследие ромбовидной формы: sizeof Большинство производных классов - PullRequest
4 голосов
/ 31 марта 2011

Я понимаю, что наследование в форме ромба вызывает неоднозначность, и этого можно избежать, используя наследование через virtual Base Classes, вопрос не в этом.Вопрос заключается в размере самого производного класса в иерархии ромбовидной формы, когда классы полиморфны.Вот пример кода и пример вывода:

#include<iostream>

using namespace std;

class Base
{
    public:
        virtual void doSomething(){}  
};

class Derived1:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived2:public virtual Base
{
    public:
       virtual void doSomething(){}
};

class Derived3:public Derived1,public Derived2
{
    public:
       virtual void doSomething(){}
};

int main()
{
    Base obj;
    Derived1 objDerived1;
    Derived2 objDerived2;
    Derived3 objDerived3;

    cout<<"\n Size of Base: "<<sizeof(obj);
    cout<<"\n Size of Derived1: "<<sizeof(objDerived1);
    cout<<"\n Size of Derived2: "<<sizeof(objDerived2);
    cout<<"\n Size of Derived3: "<<sizeof(objDerived3);

    return 0;
}

Вывод, который я получаю:

 Size of Base: 4
 Size of Derived1: 4
 Size of Derived2: 4
 Size of Derived3: 8

Как я понимаю, Base содержит функцию виртуального члена и, следовательно,
sizeof Base = размер vptr = 4 в этой среде

Аналогично случаю Derived1 & Derived2 классов.

Вот мои вопросы, связанные с приведенным выше сценарием:
Како размере Derived3 объекта класса. Означает ли это, что класс Derived3 имеет 2 vptr?
Как класс Derived3 работает с этими 2 vptr. Какие-либо идеи относительно механизма, который он использует?
Размер классовоставлены как детали реализации компилятора и не определены Стандартом (поскольку сам виртуальный механизм является деталью реализации компиляторов)?

Ответы [ 4 ]

4 голосов
/ 31 марта 2011

Да, Derived3 имеет два указателя vtable.Если вы обращаетесь к нему по значению, он использует версию Derived3, или выбирает функцию у родителя, или обозначает, что она неоднозначна, если не может принять решение.

В случае дочернего элемента,он использует vtable, соответствующий родительской 1/2, которая используется полиморфно.

Обратите внимание, что вы не правильно использовали виртуальное наследование: я считаю, что Derived1 и 2 должны наследоваться виртуально от Base.sizeof(Derived3) все еще кажется 8, потому что у него все еще есть два возможных родителя, которых можно рассматривать как Derived3.Когда вы приводите одного из родителей, компилятор на самом деле корректирует указатель объекта, чтобы иметь правильный vtable.

Также я должен отметить, что все, что связано с vtable, зависит от реализации, потому что там даже нет упоминанияvtables в стандарте.

3 голосов
/ 31 марта 2011

Небольшое исправление в вашем коде: виртуальная часть должна быть в определении производного 2 и производного 3, чтобы работать.

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

1 голос
/ 31 марта 2011

Рассмотрим немного другой случай:

struct B { virtual void f(); };
struct L : virtual B { virtual void g(); };
struct R : virtual B { virtual void h(); };
struct D : L, R {};

В типичной реализации L :: g будет находиться в той же позиции (скажем, с индексом 0) в v-таблице L, что и R: h в v-таблице R.Теперь рассмотрим, что происходит с помощью следующего кода:

D* pd = new D;
L* pl = pd;
R* pr = pd;
pl->g();
pr->h();

В последних двух строках компилятор сгенерирует код, чтобы найти адрес функции в той же позиции в виртуальной таблице.Таким образом, vtable, доступный через pl, не может быть тем же самым, что и тот (или префикс того), доступный через pr.Таким образом, для полного объекта требуется как минимум два vptr, чтобы указывать на два разных vtable.

1 голос
/ 31 марта 2011

Я думаю, вы задаетесь вопросом о том, что полностью зависит от реализации. Вы не должны предполагать что-либо о размере классов.

Редактировать: хотя любопытство - проверенное качество; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...