![](/img/trans.png)
[英]Why is base-class destructor called on derived object when destructor of derived class is non-virtual?
[英]Virtual Destructor Not called in Base as well as Derived Class
以下代码涉及4个类。
基础班是人班,有两个派生班学生和讲师。 每个人都支持两个函数:toString()和type()。 Type()返回该类的名称,而toString()打印该实例的信息(学生或讲师)。
人是抽象类,但学生和讲师都是具体的类。
我已经实现了以上两个功能。
谁能解释我的第三点? 据我所知,我利用了Lecturer构造函数中给出的SalaryTable指针,并将其分配给了我在Lecturer.h中添加的SalaryTable指针(salaryTable_)。 然后我使用salaryTable _-> annualSalary(grade_)返回薪水。 在〜Lectuere()的析构函数中,我删除了薪水表_。
这是正确的方法吗? 当我这样做时,只会调用〜Salary()析构函数,而基类的析构函数(〜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_ */
注意:请注意,我无法对.h文件进行更改。
我已经收到了很多有关销毁指针的意见。 但是我的最终问题是:为什么除SalaryTable类之外的所有其他类都没有被销毁。 我通过在所有类的析构函数中打印一个stmt进行了验证。 谁能给它一些启示。
“还添加了main.cpp文件,我也无法修改它。”
谁能解释我的第三点? 据我所知,我利用了Lecturer构造函数中给出的SalaryTable指针,并将其分配给了我在Lecturer.h中添加的SalaryTable指针(salaryTable_)。 然后我使用salaryTable _-> annualSalary(grade_)返回薪水。 在〜Lectuere()的析构函数中,我删除了薪水表_。
您的方法存在问题:第三个主题指出,讲师不拥有薪资表,并且可以在多位讲师之间共享。 像这样在构造函数中删除意味着表的唯一所有权,事实并非如此。
这可能取决于程序的其余逻辑,但是这里最好的方法之一是使共享智能指针指向表,而不是原始指针。 您的声明将变为以下内容:
// ...
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块的末尾销毁它。
这不是正确的方法:工资表是由讲师的构造函数提供给您的。 如果在讲师的析构函数中将其删除,则共享同一表的所有其他讲师将受到影响。
正确的方法是在不需要表时让创建表的调用者对其进行尝试。
最好的方法是将共享薪水表的原始指针替换为共享指针,然后可以自动跟踪其用法并在不再需要时销毁对象
您必须确定谁拥有SalaryTable
,每个Lecturer
都会在构造中收到一个指针。 有两个类似的选项。
(1)该表由另一个类/代码显式拥有(您的问题中未显示),那么Lecturer
应保持对该表( const SalaryTable*const
或SalaryTable&
或类似表)的观察指针 (或引用),该指针永远不会用于delete
和代码布局必须保证一个SalaryTable
任何前不被破坏Lecturer
观察它。
(2)您可以使用std::shared_ptr
来确保后者,但这要付出一定的代价,这也意味着SalaryTable
没有所有者,但是所有保留了shared_ptr
的代码部分都共同拥有所有权。
对我来说(1)似乎更合乎逻辑: SalaryTable
是一个不SalaryTable
任何Lecturer
的基本对象,应该在任何Lecturer
之前创建,并在任何Lecturer
之后销毁。 如果您还没有经验,我也建议避免使用shared_ptr
。
SalaryTable
实例被破坏,因为它是一个局部自动变量。
其他对象不会被销毁,因为它们是使用new
动态分配的,没有相应的delete
调用(也没有智能指针可以这样做)。
就这么简单。
顺便说一句,如其他答案中所述,您不应让对象delete
它不拥有的东西。
每个讲师仅具有一个非所有者的工资表指针。
这意味着该代码必须确保只要存在参照讲师对象,被参照薪水表就存在。 通常,这是通过智能指针完成的。 由于您无法更改标题,因此必须手动进行确认。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.