Я думаю, что это может произойти, потому что событие focus
запускается перед событием change
, поэтому следующая выбранная вами радиостанция будет сфокусирована до того, как предыдущая проверенная радиостанция инициирует событие изменения. Не цитируйте меня на этом, хотя ...
Вы могли бы сделать это следующим образом:
var isChecked = function(id) { alert(id + ': ' + $('#' + id).is(':checked')) }
$('input[name="a"]').change(function(){ isChecked('one') })
Компиляторам разрешено реализовывать это по своему усмотрению. Но обычно они следуют старой реализации 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.
Я не думаю, что стандарт дает какие-либо гарантии. Компиляторы могут создавать несколько копий функций, комбинировать копии, которые обращаются к одним и тем же смещениям памяти совершенно разных типов и т. Д. Встраивание - лишь один из наиболее очевидных случаев этого.
Но большинство компиляторов не генерируют копию кода для использования 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
, на самом деле это не сильно увеличивает размер программы).
В вашем примере здесь ничего не копируется. Обычно объект не знает, в каком классе он находится во время выполнения - что происходит, когда программа скомпилирована , компилятор говорит: «Эй, это переменная типа C, давайте посмотрим, есть ли C :: print (). Нет, хорошо, а как насчет A :: print ()? Да? Хорошо, назовите это! "
Виртуальные методы работают по-другому, в том смысле, что указатели на нужные функции хранятся в" vtable " * , на который есть ссылка в объекте. Это все равно не имеет значения, если вы работаете напрямую с C, потому что он все равно следует шагам, описанным выше. Но для указателей он мог бы сказать: «О, C :: print ()? Адрес - это первая запись в vtable». и компилятор вставляет инструкции, чтобы захватить этот адрес во время выполнения и вызвать его.
* Технически это не обязательно. Я почти уверен, что вы не найдете упоминания в стандарте "vtables"; это по определению зависит от реализации. Просто так случилось, что это был метод, который использовали первые компиляторы C ++, и он работает лучше во всех отношениях, чем другие методы, поэтому его использует почти каждый существующий компилятор C ++.
В объекте не будет храниться никакой информации для описания функции-члена.
aobject.print();
bobject.print();
cobject.print();
Компилятор просто преобразует приведенные выше операторы в прямой вызов функции print, по сути, в объекте ничего не хранится.
инструкция псевдосборки будет выглядеть, как показано ниже
00B5A2C3 call print(006de180)
Поскольку print является функцией-членом, у вас будет дополнительный параметр; этот указатель. Это будет передано, как и любой другой аргумент функции.
Просмотрите C ++ ABI , чтобы задать вопросы, касающиеся in -память раскладки вещей. Он помечен как Itanium C ++ ABI, но стал стандартным ABI для C ++, реализованным большинством компиляторов.