Вот почему динамически созданные элементы не реагируют на клики & nbsp;:
var body = $("body");
var btns = $("button");
var btnB = $("<button>B</button>");
// `<button>B</button>` is not yet in the document.
// Thus, `$("button")` gives `[<button>A</button>]`.
// Only `<button>A</button>` gets a click listener.
btns.on("click", function () {
console.log(this);
});
// Too late for `<button>B</button>`...
body.append(btnB);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
В качестве обходного пути вы должны прослушивать все клики и проверять исходный элемент & nbsp;:
var body = $("body");
var btnB = $("<button>B</button>");
var btnC = $("<button>C</button>");
// Listen to all clicks and
// check if the source element
// is a `<button></button>`.
body.on("click", function (ev) {
if ($(ev.target).is("button")) {
console.log(ev.target);
}
});
// Now you can add any number
// of `<button></button>`.
body.append(btnB);
body.append(btnC);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
Это называется «Event Delegation». Хорошие новости, это встроенная функция в jQuery: -)
var i = 11;
var body = $("body");
body.on("click", "button", function () {
var letter = (i++).toString(36).toUpperCase();
body.append($("<button>" + letter + "</button>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
Это список инициализации члена . Вы должны найти информацию об этом в любой хорошей книге C ++ .
Вы должны в большинстве случаев инициализировать все объекты-члены в списке инициализации члена ( однако обратите внимание на исключения, перечисленные в конце записи в FAQ).
Точка выгрузки из пункта часто задаваемых вопросов состоит в том, что
При прочих равных условиях ваш код будет работать быстрее, если вы используете списки инициализации, а не назначение.
blockquote>
Вы правы, это действительно способ инициализации переменных-членов. Я не уверен, что для этого есть много пользы, кроме как ясно выражая, что это инициализация. Наличие «bar = num» внутри кода может быть легко перемещено, удалено или неверно истолковано.
const
переменные-члены или переменные-члены, являющиеся ссылками, вы имеете i>, чтобы использовать список инициализаторов.
– Charles Salvia
11 November 2009 в 00:35
Другой уже объяснил вам, что синтаксис, который вы наблюдаете, называется «список инициализаторов конструктора». Этот синтаксис позволяет настраивать базовые подобъекты и субобъекты-члены класса (в отличие от разрешения инициализации по умолчанию или оставаться неинициализированным).
Я просто хочу отметить, что синтаксис, который, как вы сказали, «выглядит как вызов конструктора», не обязательно является вызовом конструктора. В языке C ++ синтаксис ()
- это всего лишь одна стандартная форма синтаксиса инициализации . Это интерпретируется по-разному для разных типов. Для типов классов с определяемым пользователем конструктором это означает одно (это действительно вызов конструктора), для типов классов без определяемого пользователем конструктора это означает другое (так называемая инициализация значения ) для пустого ()
), а для типов, не относящихся к классу, он снова означает что-то другое (так как типы некласса не имеют конструкторов).
В вашем случае член данных имеет тип int
. int
не является типом класса, поэтому он не имеет конструктора. Для типа int
этот синтаксис означает просто «инициализировать bar
со значением num
» и все. Это делается так же, как и непосредственно, никаких конструкторов, поскольку еще раз int
не является типом класса, поэтому он не может иметь никаких конструкторов.
Foo(int num): bar(num)
Эта конструкция называется списком инициализаторов членов в C ++.
Проще говоря, она инициализирует ваш член bar
значением num
.
Инициализация члена:
Foo(int num): bar(num) {};
Назначение членов:
Foo(int num)
{
bar = num;
}
Существует значительная разница между Инициализацией члена с использованием списка инициализаторов членов и присвоением ему значения внутри тела конструктора.
Когда вы инициализируете поля через список инициализаторов члена конструкторы будут вызываться один раз, и объект будет создан и инициализирован в одной операции.
Если вы используете присваивание , тогда поля будут сначала инициализированы конструкторами по умолчанию, а затем переназначены ( через оператор присваивания) с фактическими значениями.
Как вы видите, есть дополнительные накладные расходы на создание & amp; назначение в последнем, что может быть значительным для пользовательских классов.
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
Последнее фактически эквивалентно:
Foo(int num) : bar() {bar = num;}
Хотя первое эквивалентно простому:
Foo(int num): bar(num){}
Для встроенных (ваш пример кода) или членов класса POD практических накладных расходов нет.
У вас будет (довольно принудительно) использовать список инициализатора члена, если:
class MyClass
{
public:
//Reference member, has to be Initialized in Member Initializer List
int &i;
int b;
//Non static const member, must be Initialized in Member Initializer List
const int k;
//Constructor’s parameter name b is same as class data member
//Other way is to use this->b to refer to data member
MyClass(int a, int b, int c):i(a),b(b),k(c)
{
//Without Member Initializer
//this->b = b;
}
};
class MyClass2:public MyClass
{
public:
int p;
int q;
MyClass2(int x,int y,int z,int l,int m):MyClass(x,y,z),p(l),q(m)
{
}
};
int main()
{
int x = 10;
int y = 20;
int z = 30;
MyClass obj(x,y,z);
int l = 40;
int m = 50;
MyClass2 obj2(x,y,z,l,m);
return 0;
}
MyClass2
не имеет конструктора по умолчанию, поэтому он должен быть инициализирован через список инициализаторов членов. MyClass
не имеет конструктора по умолчанию, поэтому для инициализации его члену-члену нужно будет использовать список инициализаторов членов. Переменные класса-члена всегда инициализируются в том порядке, в котором они объявлены в классе.
Они не инициализируются в том порядке, в котором они указаны в Список членов Initalizer. Короче говоря, список инициализации Member не определяет порядок инициализации.
Учитывая вышеизложенное, всегда является хорошей практикой поддерживать тот же порядок членов для инициализации члена как порядок, в котором они объявлены в определении класса. Это связано с тем, что компиляторы не предупреждают, отличаются ли эти два порядка, но относительно новый пользователь может смутить список инициализаторов членов как порядок инициализации и записать код, зависящий от этого.
Это инициализация конструктора. Это правильный способ инициализации элементов в конструкторе класса, поскольку он запрещает вызов конструктора по умолчанию.
Рассмотрим эти два примера:
// Example 1
Foo(Bar b)
{
bar = b;
}
// Example 2
Foo(Bar b)
: bar(b)
{
}
В примере 1:
Bar bar(); // default constructor
bar = b; // assignment
В примере 2:
Bar bar(b) // copy constructor
Все дело в эффективности.
Это называется списком инициализации. Это альтернативный способ инициализации членов класса. Есть преимущества использования этого вместо простого назначения новых значений членам в теле конструктора, но если у вас есть члены класса, которые являются константами или ссылками , они необходимо инициализировать .
Еще не упоминается в этом потоке: начиная с C ++ 11, в списке инициализаторов членов может использоваться инициализация списка (ака. «равномерная инициализация», «согласованная инициализация»):
Foo(int num): bar{num} {}
, который имеет ту же семантику, что и инициализация списка в других контекстах.
Я не знаю, как вы могли это пропустить, это довольно просто. Это синтаксис для инициализации переменных-членов или конструкторов базового класса. Он работает для простых старых типов данных, а также для объектов класса.
Это список инициализации. Он инициализирует элементы до того, как будет запущен тело конструктора. Рассмотрим
class Foo {
public:
string str;
Foo(string &p)
{
str = p;
};
};
vs
class Foo {
public:
string str;
Foo(string &p): str(p) {};
};
. В первом примере str будет инициализироваться конструктором без аргументов
string();
перед телом конструктора Foo. Внутри конструктора foo
string& operator=( const string& s );
будет вызываться на 'str', как вы делаете str = p;
. Во втором примере str будет инициализироваться непосредственно вызовом его конструктор
string( const string& s );
с «p» в качестве аргумента.
существует другое «преимущество»
, если тип переменной-члена не поддерживает инициализацию нуля или если его ссылка (которая не может быть инициализирована нулем), тогда у вас нет выбора, кроме как предоставить список инициализации
Это список инициализации для конструктора. Вместо построения по умолчанию x
, y
и z
, а затем присваивая им значения, полученные в параметрах, эти члены будут инициализированы этими значениями сразу с места в карьер. Это может показаться не очень полезным для float
s, но это может быть довольно многопользовательский режим с настраиваемыми классами, которые дороги построить.
Это не скрыто, это синтаксис списка инициализации C ++
В принципе, в вашем случае x
будет инициализирован _x
, y
с _y
, z
с _z
.
int i(23);
,std::vector<double> emptyVec(0);
,std::vector<double> fullVec(10,23.);
и т. Д. Только с удаленным типом, конечно, потому что тип находится в объявлении члена. – Steve Jessop 11 November 2009 в 02:03