Как наследование реализовано на уровне памяти?

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

Вы могли бы сделать это следующим образом:

var isChecked = function(id) { alert(id + ': ' + $('#' + id).is(':checked')) }
$('input[name="a"]').change(function(){ isChecked('one') })

Демо: http://jsfiddle.net/elclanrs/ cD5ww /

11
задан Moeb 21 April 2010 в 05:00
поделиться

5 ответов

Компиляторам разрешено реализовывать это по своему усмотрению. Но обычно они следуют старой реализации CFront.

Для классов / объектов без наследования

Примите во внимание:

#include <iostream>

class A {
    void foo()
    {
        std::cout << "foo\n";
    }

    static int bar()
    {
        return 42;
    }
};

A a;
a.foo();
A::bar();

Компилятор изменяет эти последние три строки на что-то похожее на:

struct A a = <compiler-generated constructor>;
A_foo(a); // the "a" parameter is the "this" pointer, there are not objects as far as
          // assembly code is concerned, instead member functions (i.e., methods) are
          // simply functions that take a hidden this pointer

A_bar();  // since bar() is static, there is no need to pass the this pointer

Когда-то давно я мог предположить, что это было обработано с помощью указателей на функции в каждом созданном объекте . Однако такой подход означал бы, что каждый объект A будет содержать идентичную информацию (указатель на одну и ту же функцию), которая будет занимать много места. Компилятору достаточно легко позаботиться об этих деталях.

Для классов / объектов с невиртуальным наследованием

Конечно, это не совсем то, о чем вы спрашивали. Но мы можем расширить это до наследования, и это то, что вы ожидаете:

class B : public A {
    void blarg()
    {
        // who knows, something goes here
    }

    int bar()
    {
        return 5;
    }
};

B b;
b.blarg();
b.foo();
b.bar();

Компилятор превращает последние четыре строки в нечто вроде:

struct B b = <compiler-generated constructor>
B_blarg(b);
A_foo(b.A_portion_of_object);
B_bar(b);

Замечания по виртуальным методам

Ситуация становится немного сложнее, когда вы говорите о виртуальные методы. В этом случае каждый класс получает специфичный для класса массив указателей на функции, по одному указателю для каждой виртуальной функции. Этот массив называется vtable («виртуальная таблица»), и каждый созданный объект имеет указатель на соответствующую vtable. Вызов виртуальных функций разрешается путем поиска правильной функции для вызова в vtable.

7
ответ дан 3 December 2019 в 08:03
поделиться

Я не думаю, что стандарт дает какие-либо гарантии. Компиляторы могут создавать несколько копий функций, комбинировать копии, которые обращаются к одним и тем же смещениям памяти совершенно разных типов и т. Д. Встраивание - лишь один из наиболее очевидных случаев этого.

Но большинство компиляторов не генерируют копию кода для использования A :: print при вызове через экземпляр C. Может быть указатель на A во внутренней таблице символов компилятора для C, но во время выполнения вы, скорее всего, увидите, что:

A a; C c; a.print(); c.print();

превратился во что-то вроде:

A a;
C c;
ECX = &a; /* set up 'this' pointer */
call A::print; 
ECX = up_cast<A*>(&c); /* set up 'this' pointer */
call A::print;

, где обе инструкции вызова переходят по тому же адресу в памяти кода.

Конечно, поскольку вы попросили компилятор встроить A :: print , код, скорее всего, будет скопирован на каждый сайт вызова (но поскольку он заменяет вызов A :: print , на самом деле это не сильно увеличивает размер программы).

3
ответ дан 3 December 2019 в 08:03
поделиться

В вашем примере здесь ничего не копируется. Обычно объект не знает, в каком классе он находится во время выполнения - что происходит, когда программа скомпилирована , компилятор говорит: «Эй, это переменная типа C, давайте посмотрим, есть ли C :: print (). Нет, хорошо, а как насчет A :: print ()? Да? Хорошо, назовите это! "

Виртуальные методы работают по-другому, в том смысле, что указатели на нужные функции хранятся в" vtable " * , на который есть ссылка в объекте. Это все равно не имеет значения, если вы работаете напрямую с C, потому что он все равно следует шагам, описанным выше. Но для указателей он мог бы сказать: «О, C :: print ()? Адрес - это первая запись в vtable». и компилятор вставляет инструкции, чтобы захватить этот адрес во время выполнения и вызвать его.

* Технически это не обязательно. Я почти уверен, что вы не найдете упоминания в стандарте "vtables"; это по определению зависит от реализации. Просто так случилось, что это был метод, который использовали первые компиляторы C ++, и он работает лучше во всех отношениях, чем другие методы, поэтому его использует почти каждый существующий компилятор C ++.

1
ответ дан 3 December 2019 в 08:03
поделиться

В объекте не будет храниться никакой информации для описания функции-члена.

aobject.print();
bobject.print();
cobject.print();

Компилятор просто преобразует приведенные выше операторы в прямой вызов функции print, по сути, в объекте ничего не хранится.

инструкция псевдосборки будет выглядеть, как показано ниже

00B5A2C3   call        print(006de180)

Поскольку print является функцией-членом, у вас будет дополнительный параметр; этот указатель. Это будет передано, как и любой другой аргумент функции.

1
ответ дан 3 December 2019 в 08:03
поделиться

Просмотрите C ++ ABI , чтобы задать вопросы, касающиеся in -память раскладки вещей. Он помечен как Itanium C ++ ABI, но стал стандартным ABI для C ++, реализованным большинством компиляторов.

3
ответ дан 3 December 2019 в 08:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: