Не существует подходящего конструктора для преобразования из const char в string

Обновлено: 04.05.2024

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

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

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

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

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

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

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

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

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

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

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

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

Когда вы ДОЛЖНЫ использовать список инициализаторов членов?

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

  • В вашем классе есть ссылочный член
  • В вашем классе есть нестатический член const или
  • У вашего члена класса нет конструктора по умолчанию или
  • Для инициализации членов базового класса или
  • Когда имя параметра конструктора совпадает с именем элемента данных (на самом деле это НЕ ДОЛЖНО)

Пример кода:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Учу язык С++ по книги Р.Лафоре "Объектно-ориентированное программирование на С++". Часто замечал, что некоторый код, который написан в книге, не компилируется в Visual Studio 17 (как с другими версиями - не знаю).

Например, при компиляции следующий код

просто не компилируется, вызывая следующие ошибки:

E0415 не существует подходящего конструктора для преобразования из "const char [11]" в "ClassString**"

C4996 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.**

C2440 инициализация: невозможно преобразовать "const char [11]" в "ClassString"**

Код скопирован полностью слово в слово, изменены лишь название переменных. Неужели автор книги схалтурил? Или проблемы выражены у меня? Ведь точно такой же код без проблем компилируется в онлайн-компиляторах.

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

Кстати если речь идет об издании 2004 года, то имеет смысл почитать что-то другое, книга очень сильно отстала от реалий C++: 15 лет и три новых редакции языка.

Книга издания 2017 года. В описании написано, что весь код был протестирован на компиляторе MVC++ 6.0. Согласен, действительно старый компилятор.

2 ответа 2

Книга была написана давно, тогда, когда в языке С++ действовали стандарты C++98 или С++03, в которых разрешалось преобразование строковых литералов к типу char * . Но даже там оно являлось deprecated, и за его использование всяким Лафоре следовало бы давать по рукам.

Это преобразование было навсегда удалено из языка в стандарте С++11.

Поэтому чтобы компилировать код из этой книги вам придется использовать компилятор, работающий в режиме C++03 или ранее (или переводить современный компилятор в этот режим).

В Visual Studio 2017 нет полноценного ключа, переводящего компилятор в режим C++98 или C++03. Но разрешить требуемое устаревшее преобразование можно либо огульно, переведя настройку проекта C/C++:Language:Conformance Mode в положение No , либо более целенаправленно, указав в командной строке компилятора настройку /Zc:strictStrings- .

I have this code below and I'm getting the error upon compilation:

error: cannot convert 'const char*' to 'std::string*' for argument '1' to 'void sillyFunction(std::string*, int)'

8 Answers 8

You can now choose to sort by Trending, which boosts votes that have happened recently, helping to surface more up-to-date answers.

Trending is based off of the highest score sort and falls back to it if no posts are trending.

Don't take your parameter in as a string * try just using a const string & instead

std::string and const char* are different types. the std::string already has a conversion from string literals (ex: "Cool" ) to the actual string object. So by passing in the string literal "Cool" you are in a sense passing in a std::string object, not a pointer to one.

The reason I chose to use a const string & is mostly from personal coding practices. This minimizes stack memory usage, and since you are passing in a constant string literal, there is no need for the parameter to be modify-able.

Also don't forget if you change from a string * that you no longer need to dereference it in your cout :

To explain what the problem actually is.

While the compiler will happily arrange for a char * /C-string to be "converted" to a std::string via the appropriate std::string constructor, that's not what you've asked for.

You have asked for a pointer to an existing std::string object. By definition, what is passed to your function must be the address of an already existing std::string (or descendant) object.

You must understand pointers as a distinct type -- your function takes a pointer-to-std::string "object". While a std::string can be accessed via a pointer to std::string , the pointer itself is not a std::string , nor can it be "converted" to a std::string , nor can it be treated as a pointer-to-char (or vice-versa).

The easiest alternative is indeed a const reference to a std::string ( const std::string & ). const, in this case, because you're not doing anything to modify the string. If you were, that would be a different matter, and you'd have to consider carefully whether you intend for the caller to see your changes.

By doing this, you're saying you want a std::string object (remember, a reference to an object is that object, see C++ FAQ 8.5 in particular), which allows the compiler to invoke the appropriate constructor to create a std::string for you when the function is called with a char * (const or not).

At the same time, if someone passes you an actual std::string , the constructor is avoided and you get the same efficiency as if you had taken a pointer-to-std::string . Win-win.

Alternatively, of course, you can just take a plain std::string , but in that case you always get a copy of the string being passed in, whether it's a C-string or a std::string . Sometimes that's desirable, sometimes not. In your case, you don't do anything but print the string out, making the overhead unnecessary.

I've got a const char * returned from a processing function, and I'd like to convert/assign it to an instance of std::string for further manipulation. This seems like it should be straight-forward, but I've not been able to find any documentation showing how it should be done. Obviously, I'm missing something. Insights appreciated.

This question was caused by a problem that can no longer be reproduced or a simple typographical error. While similar questions may be on-topic here, this one was resolved in a manner unlikely to help future readers. This can often be avoided by identifying and closely inspecting the shortest program necessary to reproduce the problem before posting.

+1: Yeah -9 for this question is kind of ridiculous. The other question is slightly different because it has a length requirement which may not be relevant to many people.

5 Answers 5

You can now choose to sort by Trending, which boosts votes that have happened recently, helping to surface more up-to-date answers.

Trending is based off of the highest score sort and falls back to it if no posts are trending.

std::string has a constructor from const char * .This means that it is legal to write:

will do the trick.

I find it amusing that we chose the same example string and almost the same(just swapped) variable names :-)

@EdHeal It's not in your example, but a char* in general could be. I'm leaving a disclaimer for others. For example, I'm using the getenv() function. If the environment variable doesn't exist it will return a null. A check would be needed before constructing a string of that function's return value. This is relevant since OP says they "got a const char * returned from a processing function".

You've got a lot of options:

Note that s3 and s4 are C++11 features, if you should still work with an old or non-compliant compiler you would have to work with one of the other options.

There are three possibilities. You can use a constructor, an assignment operator or member function assign (if do not take into account member function insert though it is also can be used:) )`

Вот код, который у меня есть

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

Дополнительная информация: я использую Windows 7 и Visual Studio 2010 Ultimate.

Редактировать: Наконец-то я заставил его работать. Мне пришлось изменить настройку «Набор символов» на «Не задано», после чего все заработало. Вот обновленный код:

задан 01 фев '11, 22:02

Та же проблема, что и в прошлый раз, аргумент pvParam имеет тип void *. На этот раз нет стандартного преобразования из std :: string в void *. И использование string :: c_str () снова возвращает вам ту же проблему, это не строка Unicode, такая как std :: wstring. - Hans Passant

Я понимаю, что вы пытаетесь сказать, я думаю, но до того, как я смог добавить L в начало строкового литерала (например, L "C: /test.jpg"). Я не знаю, как это сделать, когда имею дело с переменной вместо литерала. - Chris Dibble

3 ответы

input.c_str () вернет const char *, который будет неявно преобразован в PVOID.

Передайте input.c_str () в SystemParametersInfo, и он должен работать.

* Убедитесь, что это не скомпилировано с UNICODE = 1, потому что тогда SystemParametersInfo перенаправляется на SystemParametersInfoW, который будет ожидать std :: wstring, а не std :: string.

Если вы действительно хотите принудительно использовать строку ascii даже при компиляции UNICODE, явно вызовите SystemParametersInfoA.

Вы должны вручную кастовать, потому что void * (который совпадает с PVOID ) теряет const -неспособность const char * . (PVOID)(input.c_str()) должен это сделать. - Джонатан Гринспан

хорошо, я изменил его на (PVOID) (input.c_str ()), и он компилируется, но всегда терпит неудачу. Я добавил код для печати значений input и (PVOID) input.c_str (). Для ввода C: /test.jpg вводится C: /test.jpg, а (PVOID) input.c_str () - 0017FDDC. У вас есть идеи, почему функция не работает? - Крис Диббл

вы изменили его на SystemParametersInfoA (добавьте символ «A» в конец имени функции.) - Кирк Шуп

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