Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > размер класса


Автор: rukudias 8.11.2007, 13:40
Привет Всем!
Есть класс в нем одно поле char
и один метод
почему размер класса 1 байт?

как тогда мы одращ к методу!

Есть класс в нем одно поле char
и один метод virtual
почему размер класса 1+4 байт?
это указ на таб виртуал функций?
Спасибо

Автор: Fazil6 8.11.2007, 13:52
Цитата(rukudias @  8.11.2007,  13:40 Найти цитируемый пост)
почему размер класса 1+4 байт?это указ на таб виртуал функций?

да

Автор: Alek86 8.11.2007, 14:19
оффтоп
rukudias, ты, случаем, на брэйнфаке не пишешь? ;)

Автор: bsa 8.11.2007, 14:26
Цитата(rukudias @ 8.11.2007,  13:40)
Привет Всем!
Есть класс в нем одно поле char
и один метод
почему размер класса 1 байт?

как тогда мы одращ к методу!

Очень просто. На этапе компиляции компилятор определяет какой метод должен быть вызван и подставляет его вызов. При этом методу неявно передается указатель на экземляр класса (для нестатических методов).

Автор: jonie 9.11.2007, 01:38
Цитата

Есть класс в нем одно поле char
и один метод virtual
почему размер класса 1+4 байт?
вообще гооворя довольно странно. обычно компиляторы всеже делают выравнивание по нормальной границе... а вообще все так должно быть в "пакованом" формате 8)

Автор: Dims 9.11.2007, 03:11
Потому что методы не содержатся внутри класса, а хранятся отдельно. Причём хранится ОДИН экземпляр метода для всех экземпляров класса.

В сущности, метод класса ничем не отличается от обычной глобальной функции, кроме того, что он получает ещё указатель на объект класса и кладёт его в переменную this.

То есть, например, вот такой код

Код


class A {
public:
    int field;

    void increment(int amout) {
      field += anount;
   }

}


полностью эквивалентен коду

Код


struct A {
    int field;


}

void increment(A* This, int amout) {
   This->field += anount;
}



Чтобы работать с первым методом, нужно записать имя переменной типа A, потом поставить точечку и затем записать в скобках остальные аргументы. А чтобы работать со вторым методом, нужно адрес переменной типа A передать в первом аргументе.

Какая разница, где указывается аргумент: перед точечкой или после скобочки? В структуре от этого всё равно ничего не прибавляется.

А вот виртуальная функция добавляет в структуру поле со своим адресом. Тело функции всё равно присутствует в памяти в единственном экземпляре, но зато появляется возможность косвенной адресации. То есть, если в наследнике будет переопределена эта виртуальная функция, то в поле адреса попадёт адрес другой функции. И код, написанный для базового класса, не заметив этого, вызовет не функцию базового класса, а функцию наследника.

Добавлено через 53 секунды
Тьфу, забыл точку с запятой после тела класса. Её ещё не отменили, кстати?

Автор: skyboy 9.11.2007, 03:55
Цитата(Dims @  9.11.2007,  02:11 Найти цитируемый пост)
А вот виртуальная функция добавляет в структуру поле со своим адресом. 

разве адрес вызова виртуального метода располагается не в таблице виртуальных методов? А в объекте разве хранится не указатель на всю таблицу его виртуальных методов?  smile 

Автор: Ln78 9.11.2007, 09:15
skyboy, насколько я знаю, в объекте хранятся указатели на все таблицы для всех базовых классов. Например
Код

class A1
{
   virtual int FunA1(void) {return 1;}
   virtual int FunA2(void) {return 2;}
   virtual int FunA3(void) {return 3;}
};

class B1
{
   virtual int FunB1(void) {return 11;}
   virtual int FunB2(void) {return 12;}
};

class AB2 : public A1, public B1
{
   virtual int FunAB1(void) {return 121;}
};

Размер AB2 будет 8 байт: один указатель на таблицу виртуальных методов класса А1, другой - класса B1. 

Автор: Alexeis 9.11.2007, 10:22
Цитата(Ln78 @  9.11.2007,  09:15 Найти цитируемый пост)
Размер AB2 будет 8 байт: один указатель на таблицу виртуальных методов класса А1, другой - класса B1. 

  Да нет же, таблица VMT у наследника объединяется таблицей VMT предка. У объекта только одна VMT.

Автор: skyboy 9.11.2007, 10:25
Цитата(Ln78 @  9.11.2007,  08:15 Найти цитируемый пост)
в объекте хранятся указатели на все таблицы для всех базовых классов

а зачем такое может понадобиться?

Автор: Ln78 9.11.2007, 10:32
Alexeis, по крайней мере, в VS это именно так: два указателя.

skyboy, я всех причин не знаю. Наверное, в том числе и для того, чтобы если класс наследует от двух других, имеющих одинаковую по сигнатуре функцию, у него была возможность выбрать любую из них.

P.S. Кстати, Alexeis, ты говоришь об объединении предка и потомка, а я - про разных предков.

Автор: skyboy 9.11.2007, 10:59
Цитата(Ln78 @  9.11.2007,  09:32 Найти цитируемый пост)
а я - про разных предков

да. об этом я не подумал smile

Автор: MAKCim 9.11.2007, 11:04
Цитата(Alexeis @  9.11.2007,  10:22 Найти цитируемый пост)
Да нет же, таблица VMT у наследника объединяется таблицей VMT предка. У объекта только одна VMT.

не совсем
VMT одна, но объект содержит столько указателей (указывающих на данные внутри таблицы), сколько у его класса предков
Код

class A {
public:
    virtual void d() {}
    virtual void a() {}
};

class B {
public:
    virtual void b() {}
};

class C: public A, public B {
public:
    virtual void a() {}
    virtual void c() {}
};

int main() {
    A * a = new C();
   a -> a();
    return 0;
}

Код

_ZN1CC1Ev:    /* конструктор С */
.LFB16:
    pushq   %rbp
.LCFI14:
    movq    %rsp, %rbp
.LCFI15:    
    subq    $16, %rsp
.LCFI16:
    movq    %rdi, -8(%rbp)    /* сохранение указателя на объект */
    movq    -8(%rbp), %rdi
    call    _ZN1AC2Ev    /* вызов конструктора A*/
    movq    -8(%rbp), %rdi
    addq    $8, %rdi
    call    _ZN1BC2Ev    /* вызов конструктора B */
    movl    $_ZTV1C+16, %edx    /*  адрес элемента 2 в _ZTV1C */
    movq    -8(%rbp), %rax
    movq    %rdx, (%rax)
    movl    $_ZTV1C+56, %edx    /* адрес элемента 8 в _ZTV1C */
    movq    -8(%rbp), %rax
    movq    %rdx, 8(%rax)
    leave
    ret

...
main:    /* функция main() */
    movl    $16, %edi    /* выделение 16 байт под объект (два указателя по 8 байт) */
    call    _Znwm    /* собственно выделение */
    movq    %rax, %rbx
    movq    %rbx, %rdi    /* параметр конструктора С, т. е адрес объекта */
    call    _ZN1CC1Ev    /* вызов конструктора C */
    movq    %rbx, -16(%rbp)    /* сохранение указателя на объект */
    movq    -16(%rbp), %rax
    movq    (%rax), %rax    /* получение адреса указателя на функцию A :: d() в _ZTV1C */
    addq    $8, %rax    /* т. к вызываем переопределенный метод C :: a(), переходим к следующему элементу _ZTV1C, т. е получаем адрес указателя на функцию C :: a() в _ZTV1C */
    movq    (%rax), %rax    /* получаем адрес C :: a() из элемента _ZTV1C */
    movq    -16(%rbp), %rdi    /* параметр this */
    call    *%rax    /* вызов метода С :: a() */

...
/* VMT для C */
_ZTV1C:
/* +0 */    .quad   0
/* +8 */    .quad   _ZTI1C
/* +16 */    .quad   _ZN1A1dEv    /* метод A :: d() */
/* +24 */    .quad   _ZN1C1aEv    /* метод C :: a() */
/* +32 */    .quad   _ZN1C1cEv    /* метод C :: c() */
/* +40 */    .quad   -8
/* +48 */    .quad   _ZTI1C
/* +56 */    .quad   _ZN1B1bEv    /* метод B :: b() */
    .weak   _ZTI1C

Автор: Alexeis 9.11.2007, 11:56
Ln78, а ну да, для множественного наследования нужно.

Автор: rukudias 9.11.2007, 13:10
ВСЕМ респект и уважуха! smile 

Автор: dumb 9.11.2007, 13:38
Цитата(rukudias @  9.11.2007,  13:10 Найти цитируемый пост)
ВСЕМ респект и уважуха!
кроме MAKCimа - он, негодяй, мало того что постоянно AT&T'шным ассемблером "сыплет", так теперь еще и 64-битным начал... озверел! smile читать же невозможно! smile

Автор: bsa 9.11.2007, 14:17
Цитата(dumb @ 9.11.2007,  13:38)
Цитата(rukudias @  9.11.2007,  13:10 Найти цитируемый пост)
ВСЕМ респект и уважуха!
кроме MAKCimа - он, негодяй, мало того что постоянно AT&T'шным ассемблером "сыплет", так теперь еще и 64-битным начал... озверел! smile читать же невозможно! smile

 smile 
Ну зачем же так. Я, например, тоже на этом ассемблере немного даже пишу... smile 

Автор: Dims 9.11.2007, 14:42
Цитата(skyboy @  9.11.2007,  03:55 Найти цитируемый пост)
разве адрес вызова виртуального метода располагается не в таблице виртуальных методов? А в объекте разве хранится не указатель на всю таблицу его виртуальных методов?

Ну да, я просто так для простоты сократил.

Автор: MAKCim 9.11.2007, 15:22
Цитата(dumb @  9.11.2007,  13:38 Найти цитируемый пост)
кроме MAKCimа - он, негодяй, мало того что постоянно AT&T'шным ассемблером "сыплет", так теперь еще и 64-битным начал... озверел! smile читать же невозможно!

нет, кстати, обычно для примеров я использую Intel-синтаксис + 32-ух битный формат команд
в этом примере букав много, влом было переводить  smile 
так что уж извините

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)