Вопрос о назначении конструктора по умолчанию для * this в C ?

#c #constructor

#c #constructor

Вопрос:

Я читаю некоторый текст на C . В примере текст, написанный:

 class Student {
     int no;
     char grade[M 1];
 public:
     Student();
     Student(int, const char*);
     const Studentamp; set(int, const char*);
     void display() const;
 };

Student::Student() {
    no = 0;
    grade[0] = '';
 }

 Student::Student(int n, const char* g) { 
     *this = Student(); // initialize to empty
     set(n, g);         // validate, reset if ok
 }
  

Я не понимаю эту строку: *this = Student();

Почему мы должны это делать, в то время как простой вызов Student(); также вызывает конструктор по умолчанию? Спасибо

Ответ №1:

Невозможно вызвать конструктор по умолчанию напрямую (C FAQ). ie.

 Student::Student(int n, const char* g){
Student();
set(n, g); // validate, reset if ok
}
  

не работает. Однако я также не уверен в решении, которое у вас есть.

 *this = Student()
  

вызовет Student::operator=(const Studentamp;) . В этом конкретном классе это нормально (эта функция является копией элемента по умолчанию), но это может быть не так в целом, потому что объект Student только «частично сконструирован» при вызове этого метода.

Лучше иметь частную функцию инициализации

 void Student::init() {
 no = 0;     
 grade[0] = '';
}
  

и вызовите его из обоих конструкторов.

Ответ №2:

Хотя, имхо, было бы лучше использовать общую функцию инициализации, что-то вроде этого:

 class Student {
    (...)
    private:
        void initMe();
 };

 Student::Student() {
    initMe();
 }

 Student::Student(int n, const char* g) { 
     initMe(); // initialize to empty
     set(n, g);         // validate, reset if ok
 }


void Student::initMe() {
    no = 0;
    grade[0] = '';
 }
  

Это позволило бы избежать ненужного создания объектов.

Ответ №3:

Он создает временный Student объект, а затем копирует его в *this . Я бы просто инициализировал переменные-члены как пустые во втором конструкторе. Идея в том, что вам не нужно писать один и тот же код, который дважды инициализирует переменные-члены как пустые, но здесь это довольно тривиальная проблема.

Комментарии:

1. это плохой совет. Дублирование — это плохо. Там, где этого тривиально можно избежать, это особенно непростительно. Придерживайтесь кода в вопросе, и когда вам нужно расширить класс, вам нужно добавить инициализацию только в одном месте.

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

3. хорошо, я мало что знаю о деталях конструкторов c . Но я знаю, что дублирование кода — это плохо, и если частная инициализация — лучший способ добиться этого, то это правильный путь.

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

Ответ №4:

*this = Student(); это просто инициализация переменных-членов относительно вызываемого конструктора по умолчанию. Такого дизайна следует избегать, поскольку он создает временное и копирует его содержимое.

Используйте что-то вроде приведенного ниже:

 void reset() {   // introduce this method inlined in the class
    grade[no = 0] = '';
}

Student::Student() {
  reset();   // call it when needed
 }

 Student::Student(int n, const char* g) { 
     reset(); // initialize to empty
     set(n, g);         // validate, reset if ok
 }