2014-12-27 1 views
1

Следующий код включает в себя 4 класса.Виртуальный деструктор Не вызывается в базе, а также в производном классе

  1. Основой класса является класс Person и существуют два класса Derived Student и Lecturer. Каждый человек поддерживает две функции: toString() и type(). Тип() возвращает имя этого класса, тогда как toString() печатает информацию экземпляра (Student или Lecturer).

  2. Лицо является абстрактным классом, но оба ученика и лектора являются конкретными классами.

Я реализовал две вышеуказанные функции.

  1. Многие лекторы разделяют указатель на ту же самую зарплату, что могут быть и другие SalaryTables (поддерживающие ту же функциональность) и что лекторы не владеют SalaryTable. Кроме того, каждый из них имеет некоторые дополнительные функции.

Может ли кто-нибудь объяснить мне третий пункт в одиночку? Насколько я знаю, я использовал указатель SalaryTable, указанный в конструкторе лектора, и назначил его указателю SalaryTable (payTable_), который я добавил в Lecturer.h. Затем я возвращаю зарплату, используя payTable _-> annualSalary (grade_). И в деструкторе ~ Lectuere() я удаляю payTable_.

Это правильный способ сделать это? Когда я это делаю, вызывается только деструктор ~ Salary(), и деструктор класса Base (~ Person()) и деструкторы производного класса (~ Student() & ~ Lecturer()) не вызываются. Может ли кто-нибудь объяснить мне, где я ошибаюсь?

main.cpp

int main(int argc, char* argv[]) { 

    if (argc == 1) { 
     SalaryTable st; 
     Person* arr[2]; 
     arr[0] = new Student("Apolo",5); 
     arr[1] = new Lecturer("Zeus","CO7100",33,&st); 

     for (unsigned int i=0 ; i<2 ; ++i) { 
      if (arr[i]->type() == "Student") { 
       Student* s=dynamic_cast<Student*>(arr[i]); 
       s->addMCF("blah blah"); 
       s->addMCF(""); 
       s->addMCF("Something else"); 
      } 
     } 
     for (unsigned int i=0 ; i<2 ; ++i) { 
      cout << *arr[i] << endl; 
     } 
    } 
} 

SalaryTable.h

#ifndef SALARYTABLE_H_ 
#define SALARYTABLE_H_ 

class SalaryTable { 
public: 
    SalaryTable(); 
    ~SalaryTable(); 

    unsigned int annualSalary(unsigned int grade) const; 
}; 

#endif /* SALARYTABLE_H_ */ 

Person.h

#ifndef PERSON_H_ 
#define PERSON_H_ 

#include <string> 
#include <iosfwd> 
#include <vector> 

#include "SalaryTable.h" 

using std::vector; 
using std::string; 

class Person { 
public: 
    Person() = delete; 
    Person(const Person&) = delete; 
    Person(Person&&) = delete; 

    Person(const char* name); 
    Person(const std::string& name); 
    virtual ~Person(); 

    // Return the name of the Person 
    // Should be supported by all Persons. 
    std::string name() const; 

    virtual std::string toString() const=0; 

    virtual std::string type() const=0; 

    friend std::ostream& operator<<(std::ostream&, const Person&); 
private: 
    std::string name_; 
}; 

Student.h

class Student: public Person { 
public: 
    Student() = delete; 
    Student(const Student&) = delete; 
    Student(Student&&) = delete; 

    Student(const char* name, unsigned int studentId); 
    Student(const std::string& name, unsigned int studentId); 
    virtual ~Student(); 

    void addMCF(const std::string&); 
    std::string MCF(unsigned int); 

    unsigned int id() const; 

    std::string toString() const; 
    std::string type() const; 

private: 
    unsigned int studentId_; 
    vector<string> vec_; 
}; 

Lecturer.h

class Lecturer: public Person { 
public: 
    Lecturer() = delete; 
    Lecturer(const Lecturer&) = delete; 
    Lecturer(Lecturer&&) = delete; 

    Lecturer(const char* name, const char* teaches, unsigned int grade, 
      SalaryTable*); 
    Lecturer(const std::string& name, const std::string& teaches, 
      unsigned int grade, SalaryTable*); 
    virtual ~Lecturer(); 

    void increaseGrade(); 
    unsigned int salary() const; 

    void changeModule(const std::string& newModule); 
    std::string teaches() const; 

    std::string toString() const; 
    std::string type() const; 

private: 
    string teaches_; 
    string module_; 
    unsigned int grade_; 
    SalaryTable& salaryTable_; 

}; 

#endif /* PERSON_H_ */ 

Примечание: Разновидность примечание, я не могу вносить изменения в заголовочных файлах.

Я получил много мнений за уничтожение указателя. Но мой последний вопрос: почему все другие классы, кроме класса SalaryTable, не уничтожаются. Я проверил его, напечатав stmt в деструкторе всех классов. Может кто-нибудь пролить свет на него.

«Добавлен файл main.cpp, и я тоже не могу его изменить».

+1

где код с проблемой? почему вы думаете, что мы телепатичны? –

+1

Название вопроса может быть немного вводить в заблуждение. Я полагаю, что реальный вопрос связан с управлением собственностью «Заработной платы» в каждом «Преподавателе». –

+3

Поскольку класс 'Lecturer' не имеет указателя на' SalaryTable', он должен _not_ удалить его. –

ответ

0

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

(1) таблица явно принадлежит другой класс/код (не показан в вашем вопросе), то Lecturer должен держать наблюдения указатель (или ссылки) в таблицу (а const SalaryTable*const или SalaryTable& или аналогичный) который никогда не используется для deleteи, макет кода должен гарантировать, что SalaryTable не будет уничтожен перед любым Lecturer, наблюдая его.

(2) вы можете гарантировать это последнее с помощью std::shared_ptr, но это происходит в какой-то цене, а также означает, что нет владельца к SalaryTable, но это все те части кода, которые держать shared_ptr ему совместно держать собственность.

мне (1) появляется более логично: SalaryTable является основным объектом, который существует indepedent любого Lecturer и должен быть создан до любого Lecturer и уничтожены после любого Lecturer. Я также предлагаю избегать shared_ptr, если у вас нет опыта с ним.

+1

Re 'const SalaryTabl * const', что окончательный' const' не служит никакой полезной цели. И стоит отметить, что наблюдательный указатель и константа референта не связаны, ортогональные проблемы. То есть что первая 'const' не имеет ничего общего с концепцией наблюдающего указателя. В противном случае приятно аргументированный ответ и предложение. ;-) –

+0

Я ввел ссылки на ссылки на SalaryTable в классе лектора. Так оно и есть? –

+0

Ссылка является хорошей альтернативой константе указателя. – Walter

0

Может ли кто-нибудь объяснить мне третий пункт в одиночку? Насколько я знаю, я использовал указатель SalaryTable, указанный в конструкторе лектора, и назначил его указателю SalaryTable (payTable_), который я добавил в Lecturer.h. Затем я возвращаю зарплату, используя payTable _-> annualSalary (grade_). И в деструкторе ~ Lectuere() я удаляю payTable_.

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

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

// ... 
    Lecturer(const char* name, const char* teaches, unsigned int grade, 
     std::shared_ptr<SalaryTable>); 
    Lecturer(const std::string& name, const std::string& teaches, 
     unsigned int grade, std::shared_ptr<SalaryTable>);   
    // ... 
    std::shared_ptr<SalaryTable> salaryTable_; 

И не нужно было бы их явно удалять.


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

Я получил много мнений за уничтожение указателя. Но мой последний вопрос: почему все другие классы, кроме класса SalaryTable, не уничтожаются. Я проверил его, напечатав stmt в деструкторе всех классов. Может кто-нибудь пролить свет на него.

Ну, это означает, что этот объект не обрабатывается должным образом, как это предлагается в пункте выше. Теперь, когда вы предоставили код, мы можем определить, что данная таблица выделена в стеке, что не требует дополнительного управления памятью, кроме его деструктора. Обратите внимание, что деструктор будет вызываться только после того, как st выходит за пределы области видимости, поэтому он должен быть уничтожен в конце блока if.

+0

Я мог четко понять вашу мысль. Но я боюсь, что я не могу изменить мои файлы .h. –

+0

@DhiwaTdG В этом случае вам придется учитывать другие формы управления памятью. Если вы можете гарантировать уничтожение таблиц зарплаты после лекторов, я полагаю, вы можете сохранить здесь исходные указатели. Это не самый приятный подход, но мы ничего не можем сделать, чтобы помочь без дополнительной информации. –

+0

Я ввел ссылки на ссылки на SalaryTable в классе лектора. Так оно и есть? –

0

Это неправильный путь: таблица зарплаты была предоставлена ​​вам в конструкторе лектора. Если вы удалите его в деструкторе лектора, все остальные лекторы, имеющие одну и ту же таблицу, пострадают.

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

Лучший способ wiul бы заменить сырые указатели на общую таблицу заработной платы на общих указателей, которые могут автоматически отслеживать его использование и уничтожить объект, когда он не longuer не нужен

+0

Я мог четко понять вашу мысль. Но я боюсь, что я не могу изменить мои файлы .h. –

+0

Я ввел ссылки на ссылки на SalaryTable в классе лектора. Так оно и есть? –

+0

В вашем отредактированном коде таблица зарплат является локальным объектом в блоке if. Он будет уничтожен, как только вы покинете блок if, в то время как объекты, созданные динамически с новыми, будут жить longuer. – Christophe

0

Экземпляр SalaryTable уничтожен, потому что это локальная автоматическая переменная.

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

Это так просто.


Кстати, как уже упоминалось в других ответах, вы не должны позволить объектную delete то, что он не владеет.

Каждый лектор просто имеет указатель на не имеющую право на зарплату.

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

Смежные вопросы