Создание нового объекта в C ++ - PullRequest
0 голосов
/ 03 февраля 2012

Я программист на Java / PHP, изучаю C ++.

Я создал класс с именем UserAccount и класс с именем Database.

У меня есть входной файл спять имен:

Bob
Sam
Jane
Mark
Ann

У меня есть следующий (псевдо) код:

UserAccount *ua;
while (reading through the list of names, line by line) {
    ua = new UserAccount(name); // Create a new user based on this name
    Database->add(ua); // Add the user to the database
}

Database->listAllUsers();

Вывод должен отражать входной файл.Вместо этого я получаю:

Ann
Ann
Ann
Ann
Ann

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

Ответы [ 4 ]

2 голосов
/ 03 февраля 2012

Не могли бы вы привести пример правильной реализации?

Это было бы началом:

#include <string>
#include <vector>

class UserAccount {
public:
    UserAccount(const std::string& name) : d_name(name) {}
    ...
private:
    std::string d_name;
};

class Database {
public:
    Database() : d_accounts() {}

    void add(const UserAccount& account) {
        this->d_accounts.push_back(account);
    }

    ...

private:
    std::vector<UserAccount> d_accounts;
};

void zb() {
    Database db;
    db.add(UserAccount("Bob"));
    ...
}

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

1 голос
/ 03 февраля 2012

Программа на основе меню с использованием STL & Algorithm

Вам нужен класс useraccount для хранения сведений об отдельных пользователях и класс базы данных для хранения сведений обо всех учетных записях пользователей.

используйте строки, stl, алгоритмы для эффективности.

Пример программы, управляемой с помощью меню:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

class useraccount
{
    string name;
    //other details

public:     
    void get(string str)
    {
        name=str;
    }
    void display()
    {
        cout<<name<<endl;
    }
};

void display_db(useraccount & e)
{
    e.display();
}

void main()
{
    vector<useraccount> database;
    useraccount *ptr;
    int choice;
    string name;    
    do
    {
        cout<<"\n\n1.Insert \n2.Delete\n3.Display\n4.Exit \nEnter your choice: \n";
        cin>>choice;
        switch(choice)
        {
        case 1:
            ptr=new useraccount;
            cout<<"Enter name:\n";
            cin>>name;
            ptr->get(name);
            database.push_back(*ptr);
            break;
        case 2:
            database.pop_back();
            break;
        case 3:
            for_each(database.begin(),database.end(),display_db);
            break;
        case 4:
            cout<<"Quiting";
            break;
        default:
            cout<<"wrong choice";
        }
    }while(choice!=4);
}
1 голос
/ 03 февраля 2012

В C ++, в отличие от других языков, вы должны явно думать о том, где вещи хранятся в памяти.Указатель говорит вам, где искать в памяти, чтобы найти что-то.По аналогии можно сказать, что вы смотрите на третье письмо в 5-м ряду на странице 124 книги.Если моя книга написана карандашом, я мог бы стереть слова на этой странице и заменить их другими словами, и хотя указатель остался бы прежним (то есть я смотрю на то же место в книге), на что указываетчтобы измениться.

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

Чтобы исправить это, вам нужно сделать локальную копию имени.Это можно сделать с помощью строкового класса, как в ответе @Justin.Но для целей обучения (этот код немного сложнее), вот как вы можете выделить внутреннюю память (класс строки просто сделает это за вас):

class UserAccount {
public:
    UserAccount(const char *name)
    {
        m_name = new char[strlen(name)+1];
        strcpy(m_name, name);
    }
    ~UserAccount()
    {
        delete [] m_name;
    }
private:
    char * m_name;
};

Обратите внимание, что мы сейчас используемдеструктор, потому что мы выделили память и должны снова ее освободить, когда класс будет удален.Также обратите внимание, что я не проверял, является ли переданное имя пустым, что должно быть сделано.И последнее замечание: строки неявно оканчиваются нулем, чтобы сообщить вам, когда вы достигли конца строки.Вот почему мы должны выделить большой размер - чтобы держать нулевое значение в конце строки.

Как указывал @Marc, вы также можете использовать strdup, но я подумал, что более длинное объяснение и показ явногораспределение памяти было бы полезно, чтобы лучше понять происходящее.

1 голос
/ 03 февраля 2012

Следить за моими комментариями.Скорее всего, вы столкнулись с ошибками, класс std::string даст вам поведение, гораздо более похожее на поведение в Java.

Самое простое решение - использовать строковый вызов strdup().*

В качестве альтернативы вы можете использовать std::string, но я оставлю это вашему процессу обучения.Существует много информации об указателях, это поможет вам научиться понимать указатели.

// e.g.
char *str1 = "ann";
char *str2 = "bob";
str1 = str2;
// Both equal "bob".
str1 = "carol";
// Both equal "carol"!

Удачи.

...