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

Обновлено: 04.05.2024

Что это странное : 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 не является типом класса, поэтому у него не может быть никаких конструкторов.

Операция двойного двоеточия называется операцией разрешения области видимости. Когда мы пишем ::func() (слева от оператора ничего нет), мы уточняем принадлежность к области видимости глобального пространства имён? Зачем?

Например, вы находитесь в некотором пространстве имён, скажем, std , где у вас уже есть func() . Если, находясь внутри этого пространства, просто написать func() , будет вызвана функция из пространства std : std::func() . А вам нужна другая func() , которая определена в глобальной области: ::func() .

2 ответа 2

Допустим, Ваш код работает в пространстве имён ns1 , внутри которого есть функция ns1::func() , но при этом Вам нужно вызвать функцию func() , определённую без пространства имён (в глобальном пространстве). Вот в таких случаях Вам и нужно использовать ::func() , ибо без этого уточнения компилятор вызовет ns1::func() , чего Вам не хотелось бы.

Правила поиска имен (name lookup) в С++ очень сильно отличаются для случая квалифицированных имен (т.е. с явным указанием класса или пространства имен) и неквалифицированных имен (без такого указания). Если вас чем-то не устраивает поведение неквалифицированного поиска, которое сложно, многоэтажно и включает в себя массу нюансов вроде ADL, то вы можете подавить это поведение путем указания квалифицированного имени.

В частности, в качестве частного примера, вам может понадобиться вызвать функцию ::func там, где ее имя скрыто локальной переменной int func; .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками c++ или задайте свой вопрос.

Похожие

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Site design / logo © 2022 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2022.6.23.42447

Нажимая «Принять все файлы cookie», вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Ниже приведен конструктор a struct именованный комплекс с двумя переменными-членами, действительными и мнимыми:

каково использование части после двоеточия в заголовке функции?

вы всегда можете вызвать один конструктор из другого. Скажем, например:

this относится к тому же классу, поэтому, когда мы говорим this(10) , мы на самом деле имеем в виду выполнить public mySampleClass(int Age) метод. Вышеуказанный способ вызова метода называется initializer. Таким образом, мы можем иметь не более одного инициализатора в методе.

в вашем случае он будет вызывать конструктор по умолчанию без какого-либо параметра

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

это конструктор-инициализатор который вызывает другой конструктор экземпляра непосредственно перед телом конструктора. Существует две формы инициализаторов конструктора: this и base .

base инициализатор конструктора вызывает конструктор экземпляра из прямого базового класса для вызова.

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

BTW обычно цепочка конструкторов выполняется от конструкторов с меньшим количеством параметров до конструкторов с большим количеством параметров (путем предоставления значений по умолчанию):

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

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

компилятор вызовет здесь ошибку, потому что объект "this" нельзя использовать в конструкторе для назначения X, пока не будут назначены все поля структур. За кулисами автоматически создается поле в качестве резервного хранилища для свойства X и вызывается конструктор по умолчанию для структуры инициализирует это поле (значение по умолчанию 0 в данном случае).

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

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

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

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

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

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

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

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

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

единственный правильный способ:

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

как: MyClass(m_classID = -1, m_userdata = 0);

который объявляет конструктор, который может принимать аргументы (поэтому я мог бы создать MyClass С помощью MyClass m = MyClass(3, 4) , в результате m_classID быть 3, а m_userdata быть 4). Если я не буду передавать аргументы MyClass конструктор, это приведет к созданию эквивалентного объекта для версии со списком инициализаторов.

он сигнализирует о начале списка инициализаторов.

также он не эквивалентен MyClass (m_classId=-1,m_userData=0). Это попытка определить конструктор с 2 параметрами, которые имеют значения по умолчанию. Однако значения не имеют типов, и он не должен компилироваться вообще.

Это список инициализации. В вашем примере, это скорее что-то вроде этого (что-то вроде этого - не означает, что это эквивалентно во всех случаях):

это называется список инициализации членов. Он используется для вызова суперкласса constrctors и дает вашим переменным-членам начальное значение во время их создания.

в этом случае он инициализируется m_classID -1 и m_userData до NULL.

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

Это не совсем оператор. Это часть синтаксиса конструктора.

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

постоянные члены должны быть инициализированы таким образом. Здесь также можно инициализировать не-константы, если это можно сделать с помощью одного выражения. Если для инициализации члена требуется больше кода, Вы должны поместить фактический код между <>, Чтобы сделать это.

A много людей любят ставить почти все их код конструктора в списке initilizer. У меня есть один сотрудник, который регулярно пишет классы с несколькими экранами инициализаторов, а затем ставит "<>" для кода конструктора.

это начало списка инициализаторов, который задает переменные-члены во время построения объекта. Ваш пример " MyClass (m_classID = -1, m_userdata = 0);" невозможен, поскольку вы не определили правильный конструктор, и вы все равно не сможете получить доступ к переменным-членам в списке параметров. вы могли бы иметь что-то вроде:

список инициализаторов считается лучше, чем:

Google для получения дополнительной информации.

в этом случае: да, ist эквивалентен, потому что речь идет только о примитивных типах.

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

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


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

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

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

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


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

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

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

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

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