Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++非抽象析构函数继承_C++_Inheritance_C++11 - Fatal编程技术网

C++非抽象析构函数继承

C++非抽象析构函数继承,c++,inheritance,c++11,C++,Inheritance,C++11,我以前见过这样的问题,但不是很清楚,或者和我遇到的情况不一样 我有一个抽象基类。它有一个受保护的构造函数和析构函数。它由几个完整的类型继承,这些类型也有公共构造函数和析构函数。我遇到的问题是,如果对象被基类型引用,则删除对象不会调用子析构函数 class Tree { protected: Tree(){ } public: ~Tree(){ } }; class OakTree : public Tree { public: OakTree()

我以前见过这样的问题,但不是很清楚,或者和我遇到的情况不一样

我有一个抽象基类。它有一个受保护的构造函数和析构函数。它由几个完整的类型继承,这些类型也有公共构造函数和析构函数。我遇到的问题是,如果对象被基类型引用,则删除对象不会调用子析构函数

class Tree
{
protected:
        Tree(){ }
public:
        ~Tree(){ }
};

class OakTree : public Tree
{
public:
        OakTree(){ }
        ~OakTree(){ }
};

vector<Tree*> Trees; // Store objects using the base type
Trees.push_back(new OakTree()); // Create derived object
delete Trees[0]; // OakTree desctructor does not get called

如何调用OakTree析构函数?我试着将所有的析构函数标记为虚拟,但没有成功。基类析构函数不能是抽象的,这将解决调用问题,但不会解决删除问题。

使基类析构函数成为虚拟的

否则,如果试图通过基类指针删除,将导致未定义的行为。这是有点过时的,但是Scott Meyers用有效的C++来表达这一点,第二ED:

C++语言标准在这个主题上是非常明显的:当你尝试通过基类指针删除派生类对象,基类有一个非虚析构函数作为RunyTalk做时,结果是未定义的。这意味着编译器可以生成代码来做他们喜欢做的任何事情:重新格式化你的磁盘,向你的老板发送建议性邮件,将源代码传真给你的竞争对手,等等。在运行时经常发生的事情是派生类的destrutcor从未被调用


使基类析构函数成为虚拟的

否则,如果试图通过基类指针删除,将导致未定义的行为。这是有点过时的,但是Scott Meyers用有效的C++来表达这一点,第二ED:

C++语言标准在这个主题上是非常明显的:当你尝试通过基类指针删除派生类对象,基类有一个非虚析构函数作为RunyTalk做时,结果是未定义的。这意味着编译器可以生成代码来做他们喜欢做的任何事情:重新格式化你的磁盘,向你的老板发送建议性邮件,将源代码传真给你的竞争对手,等等。在运行时经常发生的事情是派生类的destrutcor从未被调用


这是因为基类析构函数未声明为虚拟

class Tree
{
protected:
        Tree(){ }
public:
        virtual ~Tree(){ }
}

这是因为基类析构函数未声明为虚拟

class Tree
{
protected:
        Tree(){ }
public:
        virtual ~Tree(){ }
}

如果要使用多态性,则必须在基类中有一个虚拟析构函数

问题是,当您在树上调用delete时,没有人真正知道它是什么类型的树,通过使用虚拟析构函数,编译器通过指向该特定对象实例函数表的指针生成一个调用,并且您可以获得该类型的析构函数


否则标准会说这是未定义的行为,但似乎大多数情况下编译器都会生成对析构函数的调用,无论多态指针或引用的类型是什么,这就是基类。

如果要使用多态性,基类中必须有一个虚拟析构函数

问题是,当您在树上调用delete时,没有人真正知道它是什么类型的树,通过使用虚拟析构函数,编译器通过指向该特定对象实例函数表的指针生成一个调用,并且您可以获得该类型的析构函数

否则,标准会说这是未定义的行为,但似乎大多数情况下编译器都会生成对析构函数的调用,无论您的多态指针或引用是什么类型的,在您的情况下,都是基类

我想知道为什么没有人真正问作者试图用代码实现什么

是的,在基类中有一个虚拟析构函数将有助于调用析构函数,但仍然存在未定义的行为

行删除树[0];,之后您希望看到什么

或者,更确切地说,你想用这句话达到什么目的

如果试图从向量中删除该项,则可能需要:

Trees.erase(Trees.begin());
但是,如果您忘记了删除行,那么将留下内存泄漏

因此,不要在向量中使用普通指针。考虑:

std::vector< std::shared_ptr<Tree> > Trees;
Trees.push_back( std::make_shared<OakTree>() );
Trees.erase(Trees.begin());
可运行

我想知道为什么没有人真正问作者试图用代码实现什么

是的,在基类中有一个虚拟析构函数将有助于调用析构函数,但仍然存在未定义的行为

行删除树[0];,之后您希望看到什么

或者,更确切地说,你想用这句话达到什么目的

如果试图从向量中删除该项,则可能需要:

Trees.erase(Trees.begin());
但是,如果您忘记了删除行,那么将留下内存泄漏

因此,不要在向量中使用普通指针。考虑:

std::vector< std::shared_ptr<Tree> > Trees;
Trees.push_back( std::make_shared<OakTree>() );
Trees.erase(Trees.begin());

Runnable

抱歉,我在一个析构函数中出错,导致它在我的内存dum上显示内存泄漏
p让我觉得没人叫析构函数。我99%确定在这种情况下析构函数应该是虚拟的,但我把它们作为虚拟的,但这并没有解决我的内存泄漏问题。我很粗心,但是你的答案是+1。对不起,我在一个析构函数中出错,导致它在我的内存转储上显示内存泄漏,使我认为析构函数没有被调用。我99%确定在这种情况下析构函数应该是虚拟的,但我把它们作为虚拟的,但这并没有解决我的内存泄漏问题。我的回答很粗心,但你的答案是+1。这实际上是特定于实现的,我相当确定现有的实现不会随机调用函数,尤其是格式化磁盘驱动器。我测试过的编译器调用了最接近的东西,即指针T的析构函数。这太夸张了。然而,未定义的行为可能是一种安全风险,在某些情况下,可以利用这种风险来实现攻击者的各种目标。只是不要认为夸张在技术文献中有任何地位,我认为梅耶斯先生在他的许多陈述中太过努力地表现出古怪/滑稽和不必要的色彩。我越来越讨厌这种行为,因为在讲课时,渴望注意力的教授往往会花更多的时间在易受影响的年轻人面前培养花哨的形象,而不是实际教授手头的课程。迈尔斯并不孤单。在C/C++讨论中,您还将遇到恶魔从您的鼻子里飞出来,或者猴子从一个不太舒服的地方飞出来。这些都是夸大其词。它的目的是为了给人留下一个持久的印象,让人知道未定义的行为是多么不受欢迎。这种方式对我来说不太管用。更像是展示了蹩脚的幽默感。也许我更务实一点,但通过开玩笑来强调事情的严重性和重要性似乎有点自相矛盾。如果你确实是对的,他们这样做是为了教育,为什么在做了这样的陈述之后,他们在现场表演时脸上总是带着一种自满的、期待掌声、笑声和钦佩的表情?这实际上是具体实施的,我相当肯定现有的实现不会随机调用函数,尤其是格式化磁盘驱动器。我测试过的编译器调用了最接近的东西,即指针T的析构函数。这太夸张了。然而,未定义的行为可能是一种安全风险,在某些情况下,可以利用这种风险来实现攻击者的各种目标。只是不要认为夸张在技术文献中有任何地位,我认为梅耶斯先生在他的许多陈述中太过努力地表现出古怪/滑稽和不必要的色彩。我越来越讨厌这种行为,因为在讲课时,渴望注意力的教授往往会花更多的时间在易受影响的年轻人面前培养花哨的形象,而不是实际教授手头的课程。迈尔斯并不孤单。在C/C++讨论中,您还将遇到恶魔从您的鼻子里飞出来,或者猴子从一个不太舒服的地方飞出来。这些都是夸大其词。它的目的是为了给人留下一个持久的印象,让人知道未定义的行为是多么不受欢迎。这种方式对我来说不太管用。更像是展示了蹩脚的幽默感。也许我更务实一点,但通过开玩笑来强调事情的严重性和重要性似乎有点自相矛盾。如果你确实是对的,他们这样做是为了教育,为什么在做了这样的陈述之后,他们在现场表演时脸上总是带着一种自满的、期待掌声、笑声和钦佩的表情?这是一个更大项目的简化代码。基类存储一些数据,派生类以各种方式操作这些数据。派生类还具有本地资源,这些资源需要在对象生命周期结束时删除。我知道向量是如何工作的,这不是问题的一部分。内存管理呢?如果只针对析构函数,你不需要在问题中使用任何向量代码,只要提醒大家注意,我将它存储为Tree*而不是OakTree*或Tree。我们不要太挑剔了。问题得到了回答。这是一个更大项目的简化代码。基类存储一些数据,派生类以各种方式操作这些数据。派生类还具有本地资源,这些资源需要在对象生命周期结束时删除。我知道向量是如何工作的,这不是问题的一部分。内存管理呢?如果只针对析构函数,你不需要在问题中使用任何向量代码,只要提醒大家注意,我将它存储为Tree*而不是OakTree*或Tree。我们不要太挑剔了。问题得到了回答。