Ошибка. В классе тип аргумента string распознается при передаче как char.

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Есть два класса:
- Person, в котором хранится информация о владельце:

Код: Выделить всё

#ifndef PERSON_H
#define PERSON_H
#include <string>
using namespace std;
    class Person
    {
        public:
            Person();
            Person(string the_name);
            Person(const Person& the_object);
            string get_name() const;
            Person& operator =(const Person& rt_side);
            friend istream& operator >>(istream& in_stream, Person& person_object);
            friend ostream& operator <<(ostream& out_stream, const Person& person_object);
            
        private:
            string name;    //имя человека
    };
#endif
- Vehicle - базовый класс, в котром хранится инфо об авто:

Код: Выделить всё

#ifndef VEHICLE_H
#define VEHICLE_H
#include <string>
#include "person.h"
using namespace personartemenko;
    class Vehicle
    {
        public:
            Vehicle();
            Vehicle(string the_car_model, int the_cylinders, Person the_info);
            Vehicle(const Vehicle& the_object);
            ...
            Person get_person() const;
            void set_person(Person the_info);
            Vehicle& operator =(const Vehicle& right_side);

        private:
            string car_model;    //название производителя
            int cylinders;  //количество цилиндров
            Person info;    //Информация о владельце
    };
#endif
Функция set_person:

Код: Выделить всё

    void Vehicle::set_person(Person the_info)
    {
        info = the_info;
    }
При вызове:

Код: Выделить всё

Vehicle test;
test.set_person("qwer qr");
Ошибка выглядит так:
|10|error: no matching function for call to Vehicle::set_person(const char[8])'|
Если создать стринговую переменную и ее загнать в качестве аргумента, то все норм.
Как можно обойти эту проблему (интерфейс класса Person никак дополнять нельзя)?
IceFlame
Сообщения: 62
Зарегистрирован: 29 ноя 2009, 03:54

Ну если Person трогать нельзя, то определить функцию set_person с аргументом типа const char*.

Код: Выделить всё

    void Vehicle::set_person(const char* the_info)
    {
        info = Person(string(the_info));
    }
Ну или с аргументом типа const string&. Да и вообще почаще надо использовать const, да и классы целиком в функцию передавать нехорошо.
Еще можно при вызове функции set_person явно указывать конструктор Person().
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Спасибо. Буду разбираться.
Сделал через string, как вы подсказали - работает, но не знаю корректно-ли так или лучше через конструктор:

Код: Выделить всё

 void Vehicle::set_person(const string& the_info)
    {
        info = the_info;
        //info = Person(the_info);
    }
В классах с числами, а не строками, такого не было.
Да и вообще почаще надо использовать const
Я стараюсь const чаще использовать, но пока не все варианты его применения освоил.
да и классы целиком в функцию передавать нехорошо.
Но если класс является частью другого класса, то выходит в мутаторе лучше конструктор вызывать, но в объявлении функции чтобы класса явно не было?
IceFlame
Сообщения: 62
Зарегистрирован: 29 ноя 2009, 03:54

Но если класс является частью другого класса, то выходит в мутаторе лучше конструктор вызывать, но в объявлении функции чтобы класса явно не было?
Передавать его по ссылке или по указателю, иначе при каждом вызове функции будет вызываться создаваться временный объект класса в стеке. К строкам это тоже относится. Хотя благодаря подсчету ссылок, сама строка может повторно и не копироваться.
но не знаю корректно-ли так или лучше через конструктор:
Он и так, и так вызывается, но, наверное, корректнее с явным указанием.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Код: Выделить всё

info = the_info;
Здесь вызывался бы оператор присваивания класса Person, но так, как оператора присваивания с параметром const string& в классе отсутствует, то компилятор генерирует "хитрый" код. Он создаёт временный объект Person с помощью конструктора Person(string the_name), а затем вызывает оператор присваивания, который принимает тип const Person&.

Код: Выделить всё

 info = Person(the_info);
Здесь делается по сути то же самое, то есть мы имеем два вызова: сначала конструктора, затем оператора присваивания. Отличие в том, что здесь мы это делаем явно.

Самым правильным решением и всех возможных будут следующие действия:

1. Использовать первый вариант кода
2. Определить в классе Person дополнительный оператора присваивания, принимающий в качестве параметра тип const string&.

Эти шаги обеспечат однократный вызов оператора присваивания и позволят компилятору не создавать временный объект, что увеличит быстродействие программы.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Кстати, такая же проблема с конструктором.

Код: Выделить всё

Vehicle::Vehicle(string the_car_model, int the_cylinders, Person the_info)
            : car_model(the_car_model), cylinders(the_cylinders), info(Person(the_info))
    {    }

Person::Person(string the_name) : name(the_name)
    {    }

//Использование
Truck test("Auto", 7, "SOMEONE");
Изменять как-либо класс Person нельзя - т.е. не добавить функцию, не перегрузить лишний раз оператор.

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

Я догадываюсь, почему он выдает ошибку. Конструктор копирования очень похож по своей работе на конструктор с 3 аргументами (в классах-потомках от Vehicle все эти ошибки наследюутся успешно).

Код: Выделить всё

 Vehicle::Vehicle(const Vehicle& the_object)
    {
        car_model = the_object.car_model;
        cylinders = the_object.cylinders;
        info = the_object.info;
    }
На всякий случай оператор = класса Person:

Код: Выделить всё

Person& Person: :o perator =(const Person& rt_side)
    {
        if(this->name == rt_side.name)
            return *this;
        else
        {
            name = rt_side.name;
            return *this;
        }
    }
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Заработало после того, как в вызове сделал приведение к типу string: Truck test("Auto", 7, string("SOMEONE"));
И конечно же все аргументы сделал константными и передающимися по ссылке.

Вопрос в том, можно ли заставить работать конструктор без string [string("SOMEONE");]?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Если аргумент будет иметь тип const std::string&, то в него можно будет передать обычную строку за счёт того, что std::string имеет соответствующий конструктор. Как только уберёшь const, передать уже будет нельзя. Это легко объясняется, кстати. Не константная ссылка подразумевает output параметр и если бы передача обычной строки была разрешена, то внутренний код функции изменял бы временный объект, который будет автоматически удалён после завершения, так что в его изменении нет смысла.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить