Форум программистов, компьютерный форум CyberForum.ru

Конструктор класса - C++

Восстановить пароль Регистрация
 
Fareiro
15 / 15 / 1
Регистрация: 06.12.2012
Сообщений: 130
18.03.2013, 02:17     Конструктор класса #1
Добрый вечер. Поясните кто может)
Есть класс
C++
1
2
3
4
5
6
7
8
9
10
class Person
{
public:
    Person(void);
    ~Person(void);
    
    char Name[30];
    char Surname[30];
    char PESEL[11];
}
нужно сделать конструктор, с помощью которого во время создания объекта можно будет задать name, surname, pesel.

как это правильно сделать?

Добавлено через 1 минуту
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
/////main\\\\\
       
        char Name, Surname, PESEL;
    
    cout << "Enter name: ";
    cin >> Name;
    cout << "Enter surname: ";
    cin >> Surname;
    cout << "Enter PESEL: ";
    cin >> PESEL;
 
    Person* p;
    p = new Person(Name, Surname, PESEL);
.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Person::Person(char Name, char Surname, char PESEL)
{
    Person::set_name(Name);
    Person::set_surname(Surname);
    Person::set_pesel(PESEL);
}
void Person::set_name(char Name)
{
    Name = Name;
}
 
void Person::set_surname(char Surname)
{
    Surname = Surname;
}
void Person::set_pesel(char PESEL)
{
    PESEL = PESEL;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
IrineK
Заблокирован
18.03.2013, 08:07     Конструктор класса #2
Если минимально, то как-то так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#define buf 30
 
using namespace std;
 
class Person
{
public:
    Person (char*, char*, char*);
    ~Person(void);
 
    //setters
    void setName(char* N)       {strcpy(Name,N);}
    void setSurname(char* SN)   {strcpy(Surname,SN);}
    void setPESEL(char* PES)    {strcpy(PESEL,PES);}
 
    //getters
    char* getName()     {return Name;}
    char* getSurname()  {return Surname;}
    char* getPESEL()    {return PESEL;}
 
    //console dialogues
    void setConsolDialogue();
    void getConsolDialogue();
 
private:
    char Name[30];
    char Surname[30];
    char PESEL[30];
};
 
Person::Person(char* N, char* SN, char* PES)
{   setName(N);
    setSurname(SN);
    setPESEL(PES);
}
 
void Person::setConsolDialogue()
{   char *N = new char(buf);
    char *SN = new char(buf);
    char *PES = new char(buf);
    cout<<"Name:   \t";
    cin>>N;
    cout<<"Surname:\t";
    cin>>SN;
    cout<<"PESEL:  \t";
    cin>>PES;
    this->setName(N);
    this->setSurname(SN);
    this->setPESEL(PES);
}
 
void Person::getConsolDialogue()
{   cout<<"Name:   \t"<<Name<<"\n";
    cout<<"Surname:\t"<<Surname<<"\n";
    cout<<"PESEL:  \t"<<PESEL<<"\n";
}
 
 
int main()
{   Person *p = new Person("none","none","none");
    
    cout<<"Let me introduce myself :] \n";
    p->getConsolDialogue();
 
    cout<<"\nHelp me. I forgot everytihng about me :'(\n";
    p->setConsolDialogue();
 
    cout<<"\nThanks. Let me introduce myself again :-)\n";
    p->getConsolDialogue();
    
    cin.sync();cin.get();
    return 0;
}
lemegeton
 Аватар для lemegeton
2911 / 1340 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
18.03.2013, 09:45     Конструктор класса #3
Похоже, что в данной задаче подразумевается работа с нуль-терминированными строками, АКА const char *.
Вот так более-менее корректно можно работать с такими строками.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cstring>
#include <iostream>
 
class Person {
 public:
  Person(const char *name, const char *surname, const char *pesel)
    : name(strcpy(new char[strlen(name) + 1], name)),
    surname(strcpy(new char[strlen(surname) + 1], surname)),
    pesel(strcpy(new char[strlen(pesel) + 1], pesel)) {}
  Person(const Person &other)
    : name(strcpy(new char[strlen(other.name) + 1], other.name)),
    surname(strcpy(new char[strlen(other.surname) + 1], other.surname)),
    pesel(strcpy(new char[strlen(other.pesel) + 1], other.pesel)) {}
  Person &operator=(const Person &other) {
    if (this != &other) {
      setName(other.getName());
      setSurname(other.getSurname());
      setPesel(other.getPesel());
    }
    return *this;
  }
  const char *getName() const { return name; }
  const char *getSurname() const { return surname; }
  const char *getPesel() const { return pesel; }
  void setName(const char *name) {
    delete [] this->name;
    this->name = strcpy(new char[strlen(name) + 1], name);
  }
  void setSurname(const char *surname) {
    delete [] this->surname;
    this->surname = strcpy(new char[strlen(surname) + 1], surname);
  }
  void setPesel(const char *pesel) {
    delete [] this->pesel;
    this->pesel = strcpy(new char[strlen(pesel) + 1], pesel);
  }
  virtual ~Person() {
    delete [] name;
    delete [] surname;
    delete [] pesel;
  }
 private:
  char *name;
  char *surname;
  char *pesel;
};
 
std::ostream &operator<<(std::ostream &stream, const Person &person) {
  return stream << "Person{" <<
    "name='" << person.getName() << "'," <<
    "surname='" << person.getSurname() << "'," <<
    "pesel='" << person.getPesel() << "'}";
}
 
int main(int argc,char **argv)
{
  Person person("Alexy", "Nowak", "76052209940");
  std::cout << person << std::endl;
 
  // change surname
  person.setSurname("Pawlak");
  std::cout << person << std::endl;
  return 0;
}
IrineK
Заблокирован
18.03.2013, 12:00     Конструктор класса #4
После краткого ознакомления с Майерсом ) http://www.e-reading-lib.org/book.php?book=1002058
Добавляем const к указателям на строки, убираем мусор.
Не используем #define

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
using namespace std;
 
class Person
{
public:
    Person (const char*, const char*, const char*);
    ~Person(void);
 
    //setters
    void setName(const char* N)     {strcpy(Name,N);}
    void setSurname(const char* SN) {strcpy(Surname,SN);}
    void setPESEL(const char* PES)  {strcpy(PESEL,PES);}
 
    //getters
    const char* getName() const     {return Name;}
    const char* getSurname() const  {return Surname;}
    const char* getPESEL() const    {return PESEL;}
 
    //console dialogues
    void setConsolDialogue();
    void getConsolDialogue();
 
private:
    static const int buf = 30;
    char *Name;
    char *Surname;
    char *PESEL;
};
 
Person::Person(const char* N, const char* SN, const char* PES)
{   Name = new char[buf];
    Surname = new char[buf];
    PESEL = new char[buf];
    setName(N);
    setSurname(SN);
    setPESEL(PES);
}
 
Person::~Person()
{   delete []Name;
    delete []Surname;
    delete []PESEL;
}
 
void Person::setConsolDialogue()
{   char *N = new char[buf];
    char *SN = new char[buf];
    char *PES = new char[buf];
    cout<<"Name:   \t";
    cin>>N;
    cout<<"Surname:\t";
    cin>>SN;
    cout<<"PESEL:  \t";
    cin>>PES;
    this->setName(N);
    this->setSurname(SN);
    this->setPESEL(PES);
    delete []N;
    delete []SN;
    delete []PES;
}
 
void Person::getConsolDialogue()
{   cout<<"Name:   \t"<<Name<<"\n";
    cout<<"Surname:\t"<<Surname<<"\n";
    cout<<"PESEL:  \t"<<PESEL<<"\n";
}
 
int main()
{   Person *p = new Person("none","none","none");
    
    cout<<"Let me introduce myself :] \n";
    p->getConsolDialogue();
 
    cout<<"\nHelp me. I forgot everything about me :'(\n";
    p->setConsolDialogue();
 
    cout<<"\nThanks. Let me introduce myself again :-)\n";
    p->getConsolDialogue();
 
    p->Person::~Person();
 
    cin.sync();cin.get();
    return 0;
}
Fareiro
15 / 15 / 1
Регистрация: 06.12.2012
Сообщений: 130
18.03.2013, 13:41  [ТС]     Конструктор класса #5
Благодарю!
lemegeton
 Аватар для lemegeton
2911 / 1340 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
18.03.2013, 15:12     Конструктор класса #6
Цитата Сообщение от IrineK Посмотреть сообщение
p->Person::~Person();
Это что за покемон?!
Это вместо delete p;? Ну тогда оно не освобождает память, выделенную под саму p.
В то время как delete p; заодно вызовет деструктор.

Цитата Сообщение от IrineK Посмотреть сообщение
static const int buf = 30;
Это вам зачем? Вы же можете при копировании вычислить, сколько памяти надо под хранение конкретной строки с помощью strlen и не использовать больше необходимого количества памяти, заодно и не бояться, что поле может оказаться более buf символов длиной.
IrineK
Заблокирован
18.03.2013, 16:11     Конструктор класса #7
Покемон имеет право на жизнь: http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
Why not?
lemegeton
 Аватар для lemegeton
2911 / 1340 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
18.03.2013, 16:50     Конструктор класса #8
Цитата Сообщение от IrineK Посмотреть сообщение
Покемон имеет право на жизнь: http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
Why not?
Не, я догадался, что это явный вызов деструктора. Но в данном контексте он бессмысленен и не заменяет освобождения памяти. delete p;
IrineK
Заблокирован
18.03.2013, 17:41     Конструктор класса #9
Как раз память явный вызов деструктора освобождает - он ведь под это заточен в данном случае, поскольку удаляет три строки, составляющие объект.
Нужно еще занулить указатель на объект. Поэтому в строке 83 пишем
p = NULL;

Кстати, судя по коду, представленному здесь: http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
указатель нужно занулять и при использовании delete. В указанном примере это выглядит так:
delete pName;
pName = NULL;

В Visual2010 есть проблемы с использованием delete в лоб в пользовательских классах, связанные с концепцией уборки мусора. А явный вызов деструктора действует всегда - это тоже аргумент в его пользу.
lemegeton
 Аватар для lemegeton
2911 / 1340 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
18.03.2013, 23:26     Конструктор класса #10
Цитата Сообщение от IrineK Посмотреть сообщение
Как раз память явный вызов деструктора освобождает
Память, выделенную при помощи оператора new под сам объект (на который указывает this объекта) явный вызов деструктора не освобождает.

Цитата Сообщение от IrineK Посмотреть сообщение
указатель нужно занулять и при использовании delete.
Это не обязательно, но хорошая привычка. Указатель, указывающий на 0 можно смело delete, и это не вызовет исключений.

Цитата Сообщение от IrineK Посмотреть сообщение
В Visual2010 есть проблемы с использованием delete в лоб в пользовательских классах, связанные с концепцией уборки мусора. А явный вызов деструктора действует всегда - это тоже аргумент в его пользу.
Не понял. "Уборки мусора" в стандарте С++ нет.
Kuzia domovenok
 Аватар для Kuzia domovenok
1883 / 1738 / 116
Регистрация: 25.03.2012
Сообщений: 5,907
Записей в блоге: 1
18.03.2013, 23:48     Конструктор класса #11
Цитата Сообщение от IrineK Посмотреть сообщение
Как раз память явный вызов деструктора освобождает
ты не прав. Спорить бессмысленно. Явный вызов деструктора нужен очень редко. Я слышал, его используют во всяких самодельных менеджерах памяти. Сам никогда не пользовался им.

Добавлено через 4 минуты
Цитата Сообщение от IrineK Посмотреть сообщение
указатель нужно занулять
ты не прав. Указатель это та же переменная, предназначенная для хранения адресов памяти. Если тыпосле вызова delete не запишешь в неё NULL, или даже наоборот, присвоишь ей значение абракадабры(p=0xABCD; ).Ничего не произойдёт. Вот если ты попытаешься разыменовать этот указатель и записать данные по "инвалидному" адресу - жди беды.
IrineK
Заблокирован
19.03.2013, 07:28     Конструктор класса #12
Дискуссия о занулении указателей уже не раз возникала на форуме. Например, здесь: Указатели и сссылки. Надо ли обнулять? когда и как это делать?

При этом высказывания не столь категоричны, как у моих уважаемых оппонентов)
Нисколько не сомневаясь в их компетенции и их выборе, позволю себе описание процессов, происходящих при использовании delete, для более заинтересованной аудитории.

Немного "подрихтуем" последний вариант кода. Создадим функцию для непосредственного вывода объекта в потоке.
Для этого в объявлении класса среди уже имеющихся функций добавим:
C++
1
friend const ostream& operator<<(ostream& stream,const Person& obj);
и опишем ее ниже:
C++
1
2
3
4
5
const ostream& operator<<(ostream&stream,const Person& obj)
{
    stream<<obj.Name<<"\t"<<obj.Surname<<"\t"<<obj.PESEL<<"\n";
    return stream;
}
Теперь, после того, как поиграли с объектом класса, будем его удалять.
Добавим строки:
C++
1
2
3
cout<<"\nBefore delete: "<<&p<<"\t"<<p<<"\t"<<*p;
    delete p;
    cout<<"\nAfter delete: "<<&p<<"\t"<<p<<"\t"<<*p; //здесь попытка вывода *р приведет к крашу
Конечно же, мы вылетаем при попытке обращения к объекту (*р) после delete – взять нечего (память в куче освобождена), но указатель НЕ занулен (р = 0027f92c, он остался в стеке).
Адрес и значение указателя после delete мы по-прежнему получили (см.рис.1)

Объяснение: при удалении адресуемого указателем p объекта с самим указателем p, с его значением ничего не происходит. Оператор delete освобождает память в куче, указатель же p располагается в стеке, отведенная под него память будет освобождена только при выходе p из области видимости. После выполнения delete в ячейках памяти, занимаемых указателем p в стеке, будет записана та же информация — число 0027f92c — адрес уже несуществующего объекта.

Таким образом, после выполнения оператора delete мы получаем недействительный указатель (dangling pointer), указатель, который адресует несуществующий объект. Для обработки исключений вручную имеет смысл сразу после удаления объекта присвоить указателю на него значение NULL, тем самым явно идентифицировав этот указатель как ни на что не указывающий.

Попробуем так (конечно, уже без попыток добраться до *р после delete):
C++
1
2
3
4
5
cout<<"\nBefore delete: "<<&p<<"\t"<<p<<"\t"<<*p;
    delete p;
    cout<<"\nAfter delete: "<<&p<<"\t"<<p;
    p = NULL;
    cout<<"\nAfter delete and NULL: "<<&p<<"\t"<<p;
Результат - на рис.2. Указатель благополучно занулился. Можно обрабатывать, не допуская нежелательных процессов.

Возникает вопрос: почему компилятор автоматически не присваивает ссылке NULL при операции delete?
Причина - количество указателей, ссылающихся на данный объект, компилятору неизвестно. Можно занулить данный указатель, но как быть со всеми остальными? Поэтому - дело за вами, как говорит один из корифеев данного форума - "поработайте ручками" )
Миниатюры
Конструктор класса  
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.03.2013, 08:55     Конструктор класса
Еще ссылки по теме:

C++ Конструктор производного класса требует конструктор предка
Конструктор класса не видит конструктор по умолчанию другого класса C++
C++ Пример класса с конструктором и деструктором, создание экземпляра класса через конструктор с параметрами

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
lemegeton
 Аватар для lemegeton
2911 / 1340 / 133
Регистрация: 29.11.2010
Сообщений: 2,720
19.03.2013, 08:55     Конструктор класса #13
Цитата Сообщение от IrineK Посмотреть сообщение
Возникает вопрос: почему компилятор автоматически не присваивает ссылке NULL при операции delete?
Лишняя операция. Пользователь, если будет надо, сам обнулит. Можно еще попробовать составить код так, чтобы исключить обращение к уже удаленным объектам. RAII знакомо?

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

Пример, вызывающий деструктор и обнуляющий адрес, вместо освобождения памяти.
Все очень быстро закончится bad_alloc'ом.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
 
class Large {
 public:
  Large() {}
  virtual ~Large() {}
 private:
  char data[1048576];
};
 
int main(int argc,char **argv) {
  size_t counter = 0;
  while (true) {
    try {
      Large *object = new Large();
      object->Large::~Large();
      object = NULL;
      //delete object; // если память освобождать, выделять можно будет практически бесконечно долго.
    } catch (std::exception &e) {
      std::cout << "Error: " << e.what() << std::endl;
      break;
    }    
    std::cout << ++counter << " allocations made." << std::endl;
  }
  
  std::cin.get();
  return 0;
}
Yandex
Объявления
19.03.2013, 08:55     Конструктор класса
Ответ Создать тему
Опции темы

Текущее время: 16:00. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru