繁体   English   中英

虚拟析构函数在基类和派生类中未调用

[英]Virtual Destructor Not called in Base as well as Derived Class

以下代码涉及4个类。

  1. 基础班是人班,有两个派生班学生和讲师。 每个人都支持两个函数:toString()和type()。 Type()返回该类的名称,而toString()打印该实例的信息(学生或讲师)。

  2. 人是抽象类,但学生和讲师都是具体的类。

我已经实现了以上两个功能。

  1. 许多讲师将共享指向相同SalaryTable的指针,可能还有其他SalaryTables(支持相同的功能),并且讲师不拥有SalaryTable。 另外,它们每个都有一些额外的功能。

谁能解释我的第三点? 据我所知,我利用了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*constSalaryTable&或类似表)的观察指针 (或引用),该指针永远不会用于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM