Двоеточие после конструктора c

Обновлено: 25.04.2024

Насколько я могу «вывести», первая строка объявляет только имя конструктора, «::» звучит как «принадлежит» мне. А код между <> и есть тело конструктора.

Я прав в своих предположениях? "::" похоже на принадлежность, а список после параметров и тела похож на "аргументы по умолчанию" или что-то в этом роде?

ОБНОВЛЕНИЕ: Спасибо за ответы. Можно ли это назвать методами? (Думаю, нет) и в чем разница вызова их в теле конструктора

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

Наиболее частый случай такой:

Это установит для x и y значения, которые указаны в _x и _y в параметрах конструктора. Часто это лучший способ создать любые объекты, объявленные как члены данных.

Также возможно, что вы смотрели на цепочку конструкторов:

В этом случае конструктор класса вызовет конструктор своего базового класса и передаст значения x и y .

Чтобы еще больше разобрать функцию:

Оператор :: - называется оператором разрешения области видимости. По сути, это просто указывает на то, что TransparentObject является членом TransparentObject . Во-вторых, вы правильно предполагаете, что тело конструктора заключено в фигурные скобки.

ОБНОВЛЕНИЕ: Спасибо за ответы. Можно ли это назвать методами? (Думаю, нет) и в чем разница вызова их в теле конструктора

По этому поводу имеется гораздо больше информации, чем я мог бы дать вам здесь. Чаще всего вам приходится использовать списки инициализаторов, когда вы инициализируете ссылку или const , поскольку этим переменным должно быть присвоено значение сразу после создания.

Я думаю, было бы хорошо подчеркнуть тот факт, что то, что OP называет «_someMethod» или «_someOtherMethod», не является «методами», поскольку они, вероятно, являются полями-членами конструкторов класса или базового класса.

Вы довольно близки. Первая строка - это декларация. Метка слева от :: - это имя класса, и чтобы он был конструктором, имя функции должно совпадать с именем класса.

В C ++ вы можете дополнительно поставить двоеточие и некоторые начальные значения для переменных-членов перед началом тела функции. Этот метод необходимо использовать, если вы инициализируете какие-либо переменные const или передаете параметры в конструктор суперкласса.

Затем следует тело конструктора в фигурных скобках.

Для большей ясности . метод определяется как "classname :: methodname". Чтобы быть конструктором, имя метода идентично имени класса. Конструкторы также не имеют возвращаемого значения, что странно для метода.

:: Фактически означает содержит (пояснения см. В комментариях), однако _someMethods и т. Д. - это то, что называется список инициализации. Подробная информация по ссылке =]

РЕДАКТИРОВАТЬ: Извините, мое первое предложение неверно - см. Комментарии.

Нет, «::» не означает «принадлежит». Это означает «содержит». A :: b () <. >- определение метода b класса A.

Размечена ссылка на учебник. Полдня с вводной книгой по C ++ значительно уменьшит замешательство @Oscar

@mdec, предлагаю отредактировать ответ, чтобы он был правильным. Это к лучшему; никто не рассердится. Обещать. знак равно

Да, :: - это оператор области видимости C ++, который позволяет вам сообщить компилятору, к чему принадлежит функция. Использование: после объявления конструктора запускает то, что называется списком инициализации.

Код между списком аргументов и <> определяет инициализацию (некоторых) членов класса.

Инициализация в отличие от присваивания - это разные вещи - так что все это вызовы конструкторов.

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

Желательно поместить их в список инициализации. 1 это единственный способ инициализировать константные переменные 2 он гарантирует порядок, в котором они инициализируются в 3, это может быть более эффективным В противном случае реальной разницы нет.

Обычно есть несколько веских причин для использования списка инициализации. Во-первых, вы не можете установить переменные-члены, которые являются ссылками вне списка инициализации конструктора. Также, если переменной-члену требуются определенные аргументы для собственного конструктора, вы должны передать их сюда. Сравните это:

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

Члены класса, "инициализированные" внутри тела конструктора (то есть между фигурными скобками <> с использованием оператора =), технически не являются инициализацией, это присваивание. Для классов с нетривиальным конструктором / деструктором может быть дорого построить конструкцию по умолчанию, а затем изменить таким образом посредством присваивания. Для ссылочных элементов вы должны использовать список инициализаторов, поскольку их нельзя изменить с помощью оператора присваивания.

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

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

В надуманном примере ниже похоже, что намерение состоит в том, чтобы инициализировать m_b с помощью value , затем m_a с помощью m_b , но на самом деле происходит то, что инициализируется m_a с m_b (который сам еще не инициализирован), тогда m_b инициализируется с помощью value . m_b просто будет содержать мусор!

Что делает в этом конструкторе оператор двоеточия (":")? Это эквивалентно MyClass(m_classID = -1, m_userdata = 0); ?


Это список инициализации , который является частью реализации конструктора.

Это означает, что конструктор можно вызывать без параметров. Это делает его конструктором по умолчанию , т. Е. Тем, который будет вызываться по умолчанию при написании MyClass someObject; .

Эта часть : m_classID(-1), m_userdata(0) называется списком инициализации . Это способ инициализировать некоторые поля вашего объекта (все, если хотите) значениями по вашему выбору, вместо того, чтобы оставлять их неопределенными.

После выполнения списка инициализации выполняется тело конструктора (которое в вашем примере оказывается пустым). Внутри него вы можете выполнять больше назначений, но как только вы его введете, все поля уже будут инициализированы - либо случайными, неопределенными значениями, либо теми, которые вы выбрали в своем списке инициализации. Это означает, что назначения, которые вы выполняете в теле конструктора, будут не инициализацией, а изменением значений.


Это список инициализации.

К тому времени, когда вы попадете в тело конструктора, все поля уже созданы; если у них есть конструкторы по умолчанию, они уже были вызваны. Теперь, если вы присваиваете им значение в теле конструктора, вы вызываете оператор присваивания копии, что может означать освобождение и повторное получение ресурсов (например, памяти), если у объекта они есть.

Таким образом, в случае примитивных типов, таких как int, нет никаких преимуществ по сравнению с назначением их в теле конструктора. В случае объектов, у которых есть конструктор, это оптимизация производительности, поскольку позволяет избежать двух инициализаций объекта вместо одной.

Список инициализации необходим, если одно из полей является ссылкой, потому что ссылка никогда не может быть нулевой, даже в короткий промежуток времени между построением объекта и телом конструктора. Следующее вызывает ошибку C2758: «MyClass :: member_»: должен быть инициализирован в списке инициализаторов базы конструктора / члена.

Что это странное : bar(num) означает? Кажется, что это как-то инициализирует переменную-член, но я никогда раньше не видел этого синтаксиса. Это похоже на вызов функции / конструктора, но для int ? Для меня это не имеет смысла. Возможно, кто-нибудь сможет меня просветить. И, кстати, есть ли какие-нибудь другие эзотерические языковые особенности, которые вы никогда не найдете в обычной книге по C ++?

"Обычная книга по C ++", в которой это не упоминается, вероятно, является книгой, в которой кто-то подумал, что "++" будет круто смотреться на обложке . - Rasmus Kaj 10 нояб.

Эта языковая особенность вряд ли является эзотерической. Это довольно важная особенность объектного строительства. - Charles Salvia 10 нояб.

Фактически, далеко от эзотерики, у вас часто нет другого выбора, кроме как использовать списки инициализаторов. Например, если ваш класс содержит const переменную-член или ссылку, вы должны использовать список инициализаторов. - Charles Salvia 10 нояб.

Это список инициализации участников . Вы должны найти информацию об этом в любой хорошей книге по C ++ .

В большинстве случаев вам следует инициализировать все объекты-члены в списке инициализации участников (однако обратите внимание на исключения, перечисленные в конце записи часто задаваемых вопросов).

Вывод из часто задаваемых вопросов заключается в том, что

All other things being equal, your code will run faster if you use initialization lists rather than assignment.


Есть также множество других причин для использования списков инициализации. особенно когда важен порядок инициализации. Жаль, что у него такой тупой синтаксис вызова фальшивой функции. - Martin Beckett 10 нояб.

@mgb, список инициализации не определяет порядок инициализации. Переменные-члены инициализируются в том порядке, в котором они объявлены в классе, даже если это отличается от порядка инициализации в конструкторе. - ScottJ 11 нояб.

@mgb: я не думаю, что он задуман как синтаксис вызова фальшивой функции. Это синтаксис инициализации, как int i(23); , std::vector emptyVec(0); , std::vector fullVec(10,23.); и т.д. Только с типом удален, конечно, потому что тип в объявлении члена. - Steve Jessop 11 нояб.

@Martin: у него нет синтаксиса вызова функции, у него есть синтаксис конструкции (ala: new String ("Name")). Он лучше подходит для конструктора, чем Foo (int num): m_Count = 5. Не говоря уже о том, что классы в любом случае должны быть созданы на этом этапе, поскольку он инициализируется здесь. Foo (int num): Bar = num, компилируется неправильно. Кажется странным видеть Foo (int num): m_Count (num), поскольку примитивные типы не создаются. - Lee Louviere 22 апр.

Эта конструкция называется списком инициализаторов элементов в C ++.

Проще говоря, он инициализирует ваш член bar значением num .

В чем разница между инициализацией и присвоением внутри конструктора?

Инициализация члена:

Назначение участника:

Существует значительная разница между инициализацией члена с использованием списка инициализаторов членов и присвоением ему значения внутри тела конструктора.

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

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

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

Последнее фактически эквивалентно:

В то время как первое эквивалентно просто:

Для встроенных (пример вашего кода) или членов класса POD практических накладных расходов нет.

Когда вам НЕОБХОДИМО использовать список инициализаторов участников?

Вам придется (скорее вынужденно) использовать список инициализаторов участников, если:

  • В вашем классе есть ссылочный член
  • Ваш класс имеет нестатический константный член или
  • У вашего члена класса нет конструктора по умолчанию или
  • Для инициализации членов базового класса или
  • Когда имя параметра конструктора такое же, как член данных (на самом деле это НЕ ОБЯЗАТЕЛЬНО)

Пример кода:

  • MyClass2 не имеет конструктора по умолчанию, поэтому его нужно инициализировать с помощью списка инициализаторов членов.
  • Базовый класс MyClass не имеет конструктора по умолчанию, поэтому для инициализации его члена потребуется использовать список инициализаторов членов.

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

Переменные-члены класса всегда инициализируются в том порядке, в котором они объявлены в классе.

Они не инициализируются в том порядке, в котором они указаны в списке инициализаторов элементов.
Короче говоря, список инициализации членов не определяет порядок инициализации.

Учитывая вышеизложенное, всегда рекомендуется поддерживать тот же порядок членов для инициализации членов, что и порядок, в котором они объявлены в определении класса. Это связано с тем, что компиляторы не предупреждают, если два порядка различаются, но относительно новый пользователь может запутать список инициализаторов членов как порядок инициализации и написать некоторый код, зависящий от этого.


@nils Это лучший ответ на данный момент. Указанный Алсом порядок инициализации также чрезвычайно важен, хотя компилятор Visual Studio ничего об этом не скажет, другой компилятор, такой как gcc, выйдет из строя. Также важно отметить, что в зависимости от вашего компилятора и ситуации не всегда верно, что это улучшит производительность или будет более эффективным. - ForceMagic 14 марта '12 в 7:21

@ ryf9059: Как вы думаете, почему это будет неудобно? Вы все равно должны перечислить их, так почему бы не в том же порядке, что и в декларации. - Alok Save 07 янв.

это должен был быть ответ. слава богу, я прокрутил вниз, иначе я бы пропустил это. - Coffee_lover 13 авг.

@AlokSave MyClass (int a, int b, int c): i (a), b (b), k (c) // Без инициализатора члена // this-> b = b; > он должен быть таким: MyClass (int &a , int b, int c): i (a), b (b), k (c) // Без инициализатора члена // this-> b = b; > и соответствующие изменения в объявлении и вызове. без этого изменения i будет ссылаться на, a но a не может ссылаться, x поскольку он содержит только значение, x поэтому косвенно i не может ссылаться на x . поэтому, если мы изменим значение, i оно просто изменится, a но не x - Abhishek Mane 15 мая в 11:42

Это инициализация конструктора. Это правильный способ инициализации членов в конструкторе класса, поскольку он предотвращает вызов конструктора по умолчанию.

Рассмотрим эти два примера:

Все дело в эффективности.


Я бы не сказал, что речь идет об эффективности. Речь идет о способе инициализации чего-то, что требует инициализации, но не может быть инициализировано по умолчанию. Почему-то в качестве примеров упоминаются константы и ссылки, тогда как наиболее очевидным примером могут быть классы без конструкторов по умолчанию. - AnT 11 нояб.

Мы оба правы; в его примере вы могли бы привести доводы в пользу эффективности; для конструктора const / reference / no default - это одновременно и эффективность, и необходимость. Я поддержал ответ ниже из-за этого :) [голос Фарнсворта] Он может делать и другие вещи. Почему бы и нет? - Josh 11 нояб.

@LightnessRacesinOrbit Просто любопытно узнать: что это должно быть по вашему мнению? - ajaysinghnegi 02 авг.

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

@LightnessRacesinOrbit - точка взята, но точка констант или ссылок все еще действительна в моем ответе. - LeopardSkinPillBoxHat 1 мая '13 в 10:19

В основном, в вашем случае, x будет инициализирован _x , y с _y , z с _z .

Другой уже объяснил вам, что синтаксис, который вы наблюдаете, называется «список инициализаторов конструктора». Этот синтаксис позволяет вам индивидуально инициализировать базовые подобъекты и подобъекты-члены класса (в отличие от разрешения им инициализировать по умолчанию или оставаться неинициализированными).

Я просто хочу отметить, что синтаксис, который, как вы сказали, «выглядит как вызов конструктора», не обязательно является вызовом конструктора. В языке C ++ () синтаксис - это всего лишь одна стандартная форма синтаксиса инициализации . Для разных типов он интерпретируется по-разному. Для типов классов с определяемым пользователем конструктором это означает одно (это действительно вызов конструктора), для типов классов без определяемого пользователем конструктора это означает другое (так называемая инициализация значения ) для пустого () ), а для неклассовых типов это снова означает нечто иное (поскольку неклассовые типы не имеют конструкторов).

В вашем случае элемент данных имеет тип int . int не является типом класса, поэтому у него нет конструктора. Для типа int этот синтаксис означает просто «инициализировать bar значением num » и все. Это делается именно так, напрямую, без использования конструкторов, поскольку, опять же, int не является типом класса, поэтому у него не может быть никаких конструкторов.

Двоеточие указывает на initializer list вашего конструктора.
Это позволяет вам инициализировать переменные-члены вашего класса.

Ниже примерно одинаково (но менее эффективно, чем Initializer List ):

Другие решения

Если вам нужна краткая исполнительная сводка списков инициализаторов, то вы идете: Список инициализаторов может содержать вызовы конструкторов базового класса и вызовы конструкторов переменных-членов.

Зачем тебе такая вещь? Ну, много причин.

Обратите внимание, что код довольно упрощен и содержит немного глупости (например, Name учебный класс). Цель состоит в том, чтобы просто показать, как работают списки инициализаторов, а не в том, чтобы писать причудливый код или использовать все возможные функции C ++.

Строительство базового класса

Представьте, что у вас есть базовый класс, для создания которого требуются некоторые параметры. Нет другого способа передать параметры, необходимые его конструктору, так как к тому времени < это открывает тело конструктора «execute» (простите за несколько неэффективное использование «execute» в этом контексте), базовый класс уже создан:

Конструкция члена, который является экземпляром класса

Точно так же, возможно, у вас есть члены класса, которые имеют конструкторы, которые требуют аргументов. Проблема похожа: где вы могли бы вызывать эти конструкторы для передачи аргументов и как? Ответ находится в списке инициализатора. Давайте расширим наш предыдущий пример:

Эффективная инициализация переменных-членов

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

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

Поскольку в Си конструкторы всех базовых классов и всех переменных-членов должны завершиться до того, как ваше тело конструктора начнет выполняться, это может означать, что в одном из этих конструкторов будет выполнен значительный объем работы. Вся эта работа может быть потеряна при назначении нового значения одной из этих переменных-членов.

Таким образом, вы можете инициализировать переменные-члены (независимо от их типа), передав необходимые значения в списке инициализатора конструктора. Давайте переделаем наш последний пример:

Посмотрите, как мы немного изменили инициализацию вещей. Хотя наши программы работают идентично, теперь они ведут себя совсем по-другому. Чтобы понять почему, давайте добавим в класс еще один класс:

Что означает этот странный : bar(num) ? Кажется, что это как-то инициализирует переменную-член, но я никогда раньше не видел этого синтаксиса. Похоже на вызов функции / конструктора, но для int ? Для меня это не имеет смысла. Возможно, кто-нибудь сможет меня просветить. И, кстати, есть ли какие-нибудь другие эзотерические языковые особенности, которые вы никогда не найдете в обычной книге по C ++?

Это список инициализации участников . Вы должны найти информацию об этом в любой хорошей книге по C ++.

В большинстве случаев следует инициализировать все объекты-члены в списке инициализации элементов ( однако обратите внимание на исключения, перечисленные в конце раздела часто задаваемых вопросов).

Вывод из часто задаваемых вопросов заключается в том, что

При прочих равных, ваш код будет работать быстрее, если вы будете использовать списки инициализации, а не присваивание.

По сути, в вашем случае x будет инициализирован с помощью _x , y с помощью _y , z с помощью _z .

Эта конструкция называется Список инициализаторов элементов в C ++.

Проще говоря, он инициализирует ваш член bar значением num .

В чем разница между инициализацией и присвоением внутри конструктора?

Инициализация участника:

Назначение участника:

Существует значительная разница между инициализацией члена с использованием списка инициализаторов членов и присвоением ему значения внутри тела конструктора.

Когда вам НЕОБХОДИМО использовать список инициализаторов участников?

Вам придется (скорее вынужденно) использовать список инициализаторов участников, если:

  • В вашем классе есть ссылочный член
  • Ваш класс имеет нестатический константный член или
  • У вашего члена класса нет конструктора по умолчанию или
  • Для инициализации членов базового класса или
  • Когда имя параметра конструктора такое же, как и член данных (на самом деле это НЕ ОБЯЗАТЕЛЬНО)

Пример кода:

  • MyClass2 не имеет конструктора по умолчанию, поэтому его нужно инициализировать с помощью списка инициализаторов членов.
  • Базовый класс MyClass не имеет конструктора по умолчанию, поэтому для инициализации его члена потребуется использовать список инициализаторов членов.

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

Переменные-члены класса всегда инициализируются в том порядке, в котором они объявлены в классе.

Они не инициализируются в том порядке, в котором они указаны в списке инициализаторов участников.
Короче говоря, список инициализации членов не определяет порядок инициализации.

Учитывая вышеизложенное, всегда рекомендуется поддерживать тот же порядок элементов для инициализации элемента, что и порядок, в котором они объявлены в определении класса. Это связано с тем, что компиляторы не предупреждают, если два порядка различаются, но относительно новый пользователь может запутать список инициализаторов членов как порядок инициализации и написать некоторый код, зависящий от этого.

Это инициализация конструктора. Это правильный способ инициализации членов в конструкторе класса, поскольку он предотвращает вызов конструктора по умолчанию.

Рассмотрим эти два примера:

Все дело в эффективности.

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

Другой уже объяснил вам, что синтаксис, который вы наблюдаете, называется «список инициализаторов конструктора». Этот синтаксис позволяет вам индивидуально инициализировать базовые подобъекты и подобъекты-члены класса (в отличие от разрешения им инициализировать по умолчанию или оставаться неинициализированными).

Я просто хочу отметить, что синтаксис, который, как вы сказали, «выглядит как вызов конструктора», не обязательно является вызовом конструктора. В языке C ++ синтаксис () - это всего лишь одна стандартная форма синтаксиса инициализации . Для разных типов он интерпретируется по-разному. Для типов классов с определяемым пользователем конструктором это означает одно (это действительно вызов конструктора), для типов классов без определяемого пользователем конструктора это означает другое (так называемый инициализация значения ) для пустых () ) и для неклассовых типы это снова означает что-то другое (поскольку у неклассовых типов нет конструкторов).

В вашем случае элемент данных имеет тип int . int не является типом класса, поэтому у него нет конструктора. Для типа int этот синтаксис означает просто "инициализировать bar значением num " и все. Это делается именно так, напрямую, без использования конструкторов, поскольку, опять же, int не является типом класса, поэтому у него не может быть никаких конструкторов.

Не знаю, как вы могли пропустить этот, он довольно простой. Это синтаксис для инициализации переменных-членов или конструкторов базовых классов. Он работает как с простыми старыми типами данных, так и с объектами классов.

Это список инициализации. Он инициализирует члены перед запуском тела конструктора. Рассматривать

В первом примере str будет инициализирован конструктором без аргументов.

Перед телом конструктора Foo. Внутри конструктора foo

Будет вызываться на 'str', как вы делаете str = p;

Во втором примере str будет инициализироваться напрямую путем вызова его конструктора.

Вы правы, это действительно способ инициализировать переменные-члены. Я не уверен, что в этом есть большая польза, кроме четкого указания, что это инициализация. Наличие «bar = num» внутри кода может быть гораздо проще перемещать, удалять или неправильно интерпретировать.

Есть еще одно "преимущество"

Если тип переменной-члена не поддерживает нулевую инициализацию или если это ссылка (которая не может быть инициализирована нулевым значением), у вас нет другого выбора, кроме как предоставить список инициализации

Это список инициализации конструктора. Вместо создания по умолчанию x , y и z и последующего присвоения им значений, полученных в параметрах, эти элементы будут сразу же инициализированы этими значениями. Это может показаться не очень полезным для float s, но может значительно сэкономить время с пользовательскими классами, создание которых требует больших затрат.

Еще не упомянуто в этом потоке: начиная с C ++ 11, список инициализаторов членов может использовать инициализацию списка (также известную как «равномерная инициализация», «инициализация в фигурных скобках»):

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

Читайте также: