Конструкторы для объектов C ++ - PullRequest
0 голосов
/ 18 мая 2010

У меня есть класс Person следующим образом:

class Person {   
    char* name;
    int age;
};

Теперь мне нужно добавить два конструктора. Один, не имеющий аргументов, вставляет значения поля в динамически распределяемые ресурсы. Второе получение (char *, int) аргументов, инициализированных списком инициализации. Последняя часть - определить деструктор, показывающий информацию об уничтожении объектов и освобождении динамически распределенных ресурсов. Как выполнить эту задачу?

Вот что у меня уже есть:

class Person {   
    char* name;
    int age;
public:
    Person(){
        this->name = new *char;
        this->age = new int;
    }

    Person(char* c, int i){
    }
};

Ответы [ 5 ]

3 голосов
/ 18 мая 2010

В конструкторе по умолчанию выделение массива char должно включать его желаемый размер, например,

this->name = new char[32];

Обратите внимание, что в этот размер входит завершающий символ 0, поэтому эффективная длина имен, которые вы можете сохранить в этом массиве, равна 31.

В параметризованном конструкторе вы можете просто назначить заданные параметры членам вашего класса.

В деструкторе вам необходимо освободить динамически распределенные ресурсы - обязательно используйте delete[] только тогда, когда освобождает память, выделенную с помощью new[]:

~Person(){
    std::cout << "Destroying resources" << std::endl;
    delete[] name;
    delete age;
}

Обновление: Я пропустил это: если вы хотите выделить age динамически, вы должны объявить его как int* age.

Я предполагаю, что цель этого упражнения - практиковать динамическое распределение / освобождение; в этом контексте это нормально. Однако, в общем случае, не рекомендуется динамически распределять int с, и вместо char* вы почти всегда должны использовать std::string, который автоматически и безопасно обрабатывает выделение памяти.

2 голосов
/ 18 мая 2010

Используя класс C ++ string, вы можете забыть о ручном (и опасном) управлении памятью:

class Person {
    public:
        Person () : name_(""), age_(0) { }
        Person (const std::string& name, int age) : name_(name), age_(age) { }
    // There is no need for the destructor as the memory is managed by the string class.
};

Также смотрите эту ссылку по той причине, что вы всегда должны использовать список инициализации вместо присваиваний в конструкторе.

1 голос
/ 18 мая 2010

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

Конечно, вы можете изменить тип age на int*. Но я бы не стал этого делать, это бесполезно. Непонятно, действительно ли присвоение запрашивает динамическое распределение (и если да - , почему ?).

Для name, с другой стороны, вы можете продолжить, как отмечено @Péter. Но, опять же, это не очень хорошее решение в большинстве случаев, потому что C ++ предлагает класс string, который хорошо переносит манипуляции со строками в класс. Если назначение разрешает это, используйте string вместо char* и динамическое выделение памяти.

0 голосов
/ 18 мая 2010

Я рекомендую использовать строковый класс вместо char *.

Примерно так:

class Person
{
 public:
  Person() : name(""), age(0) {}
  Person(const string& n, int a) : name(n), age(a) {}

  // whatever here.

  ~Person() {} // do nothing

 private:
  string name;
  int age;
};
0 голосов
/ 18 мая 2010

Вы также можете выделить только ту память, которая вам нужна, чтобы скопировать имя, когда вы хотите установить его. Также не забудьте освободить выделенный буфер, когда объект будет уничтожен!

class Person {   
    char* name;
    int age;
public:
    Person(){
        this->name = NULL;
        this->age = 0; // no need to allocate memory for basic types
    }

    ~Person(){
        delete [] name;
    }

    set(char* c, int i){
        this->age = i;

        // copy name if input pointer name is valid
        if (c != NULL){
            // if memory have already been allocated : delete first
            if (this->name != NULL){
                delete [] name;
                name = NULL;
            }
            // allocate memory : 1 more char for the trailing '\0'
            this->name = new char[strlen(c)+1];
            // copy string
            strcpy(this->name,c);
        }
    }
};

Изменить и ответить на замечания:

  • Упрощенный деструктор после предложения Конрада Рудольфа
  • Я склонен всегда устанавливать нераспределенные и освобожденные указатели в NULL, чтобы избежать случайного выбора областей памяти, когда указатель используется неправильно, а нераспределенные указатели также легче обнаружить в отладчике.
  • Я не обращал внимания на то, что второй метод был конструктором, я думал, что это установщик ... изменил его.
...