2016-11-30 3 views
0

Я создаю класс с именем Employee, у меня есть Name как string. вот мой класс объявляя:Ошибка при создании строки в функции класса

class Employee 
{ 
    string Name; 
public: 
    Employee(); 
    void SetName(string); 
    void StringToEmployee(string); 
    ~Employee(); 
} 

это определение StringToEmployee(string) метода:

void Employee::StringToEmployee(string s) 
{ 
    char *first = s, *end = s+strlen(s), *last = NULL; 
    last = find(first, end, ','); 
    string temp(first, last- first); 
    SetName(temp); 
} 

ошибка происходит, когда я отладки линии string temp(first, last- first), это, кажется, компилятор не позволяет мне построить новая строка в методе. потому что я также изменился на string temp;, затем temp.assign(first, last-first). ошибка все еще сохраняется. Как я могу создать новую строку в методе?

+1

Функция ['std :: strlen'] (http://en.cppreference.com/w/cpp/string/byte/strlen) является функцией C. В качестве входных данных ему требуется строка с байтом с нулевым завершением. То есть указатель на 'char'. Вместо этого попробуйте использовать функции '' std :: string' '(http://en.cppreference.com/w/cpp/string/basic_string). –

+0

Что у вас есть «строка», определяемая как в первую очередь? Где находится остальная часть вашего [MCVE] (https://stackoverflow.com/help/mcve)? И, что это за ошибка? – Useless

ответ

0

По какой-либо причине вы хотите оспаривать std::string до char*. Судя по другому коду, вы хотите работать с сырым char массива, таким образом, вы должны поставить правильные указатели на first и last, как это:

char *first = &s[0], *end = (&s[0]) + strlen(s.c_str()), *last = NULL; 

И эта часть:

string temp(first, last- first); 

является неверно, потому что last - first - указатель, и, как я понимаю, вы хотите использовать конструктор std::string(const char*, size_t). Но вместо этого вы используете конструктор на основе итератора, и система правильно умирает, потому что первый указатель больше, чем второй.

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

void Employee::StringToEmployee(string s) 
{ 
    auto found = find(s.begin(), s.end(), ','); 
    string temp(s.begin(), found); 
    SetName(temp); 
} 
1

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

Во-первых, реализация StringToEmployee следует переписать следующим образом:

void Employee::StringToEmployee(std::string s) 
{ 
    const std::string temp(s.begin(), 
          std::find(s.begin(), s.end(), ','); 
    SetName(temp); 
} 

Но так как вы не изменяем параметр s и не нужна копия этого, вы должны передать его постоянной ссылке:

void Employee::StringToEmployee(const std::string& s) 
{ 
    const std::string temp(s.begin(), 
          std::find(s.begin(), s.end(), ','); 
    SetName(temp); 
} 

Кроме того, вы должны рассмотреть вопрос о перепроектировании вашего класса Employee. В настоящее время у вас есть конструктор по умолчанию, который создает недопустимый объект Employee, а затем у вас есть функции-члены, которые позволяют вам превратить этот недопустимый объект Employee в действительный по настройкам его членов. Вместо этого у вас может быть конструктор, который выполнил всю эту инициализацию для вас за один шаг. Не только ваш код будет более чистым и понятным, но он будет более эффективным!

Может быть что-то вроде:

class Employee 
{ 
    std::string Name;       // name of this employee 

public: 
    Employee(const std::string& name);   // create Employee with specified name 
    void SetName(const std::string& newName); // change this employee's name 
    ~Employee(); 
}; 



Employee::Employee(const std::string& name) 
    : Name(s.begin(), std::find(s.begin(), s.end(), ',')) 
{ } 

void Employee::SetName(const std::string& newName) 
{ 
    Name = std::string(s.begin(), std::find(s.begin(), s.end(), ',')); 
} 

Employee::~Employee() 
{ } 

Несколько быстрых заметок:

  • Вы увидите, что я всегда в явном виде выписать std:: всякий раз, когда я использую класс из пространства имен из стандартной библиотеки. Это действительно хорошая привычка, чтобы войти, и на самом деле не так сложно напечатать дополнительные 5 символов. Это особенно важно, потому что using namespace std; - a really bad habit to get into.
  • Передаю объекты (например, строки), которые мне не нужно изменять или иметь копию внутри метода с помощью постоянной ссылки. Это легче рассуждать, а также потенциально более эффективно (поскольку оно позволяет избежать ненужных копий).
  • Внутри конструктора я использовал то, что может показаться забавным синтаксисом, включая двоеточие и некоторые круглые скобки. Это называется member initialization list, и это то, к чему вы должны привыкнуть. Это стандартный способ для конструктора класса инициализировать свои переменные-члены.