Почему c ++ не распознает строку при попытке преобразовать ее в другой тип? - PullRequest
4 голосов
/ 10 сентября 2011

У меня есть довольно простой класс, который выглядит так:

class Person {
    public:

        Person(string name): _name(name) {};

        void greet(const Person& person) const {
            cout << "Hello, " <<  person._name << "!" << endl;
        };

    private:
        string _name;
};

Обратите внимание, что метод greet принимает параметр типа Person. Когда я передаю ему Person объект, он работает как положено. Теперь давайте передадим ему string в качестве параметра следующим образом:

Person maher("maher");
maher.greet("sam");

При попытке запустить этот код в QT (на машине с Ubuntu) выдается следующая ошибка: no matching function for call to ‘Person::greet(const char [4])’

Мне удалось устранить эту ошибку, приведя строку следующим образом: maher.greet(string("sam"));

У меня следующий вопрос: почему c ++ не «видит» , что я передаю строку методу greet? Связано ли это с тем, что метод greet принимает объект Person?

Ответы [ 6 ]

6 голосов
/ 10 сентября 2011

maher - это const char[6], а sam - это const char[4], и оба неявно уменьшаются до const char *, но на самом деле ни один из них не является std::string.

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

Вот что происходит, когда вы вызываете конструктор: вы передаете const char[6], который автоматически затухает до const char *; тип цели std::string, в котором есть конструктор, который принимает const char *; такой конструктор вызывается, и конструктор Person правильно получает его параметр std::string.

Во втором случае этого не происходит: Person не имеет конструктора, который принимает const char *, а только конструктора, который принимает std::string. Чтобы достичь нужного Person типа, компилятор должен сначала преобразовать const char * в std::string, а затем вызвать конструктор Person. Это двойное преобразование недопустимо, главным образом потому, что разрешение перегрузки превратилось бы в полный беспорядок (что уже есть) со множеством неоднозначных случаев.

Если вы хотите разрешить вызов greet со строкой в ​​стиле C, вы должны либо:

  • создать конструктор для Person, который принимает строку в стиле C (const char *), так что она может быть построена непосредственно из const char *, без прохождения запрещенного дополнительного преобразования

  • создать еще одну перегрузку для greet, чтобы принять std::string.

С другой стороны, IMO более чистая альтернатива - просто оставить все как есть; звонящий просто должен написать

maher.greet(std::string("sam"));
4 голосов
/ 10 сентября 2011

Вы не передаете std::string, вы передаете строку в стиле C с типом const char*.Для этого тоже добавьте конструктор:

Person(string name): _name(name) {};
Person(const char *name): _name(name) {};

Обратите внимание, что хотя const char* автоматически может преобразовать в std::string, в этом случае это будет означать 2 преобразования (const char *> std::string> Person), что недопустимо.

3 голосов
/ 10 сентября 2011
maher.greet("sam");

Для этого требуется два преобразования:

  • Во-первых, от const char[4] до std::string, чтобы можно было вызвать Person(string).
  • Затем std::string до Person, чтобы можно было вызвать greet(const Person&).

Но преобразование цепочек не допускается.

Таким образом, вы либо предоставляете конструктор Person(const char*), либо передаете std::string, чтобы избежать первого преобразования (перечислено выше):

  • Если вы предоставите конструктор Person(const char*), const char[4] будет непосредственно преобразован в Person, который затем будет передан в greet().
  • Но если вы передадите std::string в greet (), std::string преобразуется в Person с использованием существующего конструктора в вашем коде, а затем объект person будет в конечном итоге передан в greet().

В обоих случаях существует только одно преобразование.

Или просто напишите:

//convert const char[4] to std::string manually.
maher.greet(std::string("sam")); 
0 голосов
/ 10 сентября 2011

Вы можете переопределить метод, чтобы принять строку.

void greet(const string name) const {
    cout << "Hello, " <<  name << "!" << endl;
};
0 голосов
/ 10 сентября 2011

Имеет ли это какое-либо отношение к тому факту, что метод greet принимает объект Person?
Да,

Вы можете передать строку в метод greet(), потому что в вашем классе Person есть конструктор, который создает объект Person через строку, переданную ему.

Передача char[4] требует char[4] сначала строковому объекту и затем применить вышеупомянутое преобразование. Эта цепочка преобразований не допускается и, следовательно,

0 голосов
/ 10 сентября 2011

Это абсолютно "видит", что вы передаете строку, и в этом проблема.У вас нет метода, который принимает строку в качестве входных данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...