C++ 何时可以安全地从C+;中的基类继承+;
因此,我在任何地方都能找到的基本规则是,要从基类继承,基类必须有一个虚拟析构函数,以便以下工作:C++ 何时可以安全地从C+;中的基类继承+;,c++,inheritance,C++,Inheritance,因此,我在任何地方都能找到的基本规则是,要从基类继承,基类必须有一个虚拟析构函数,以便以下工作: Base *base = new Inherited(); delete base; 然而,我确信我至少看到了另一种允许安全继承的可能性。然而,我在任何地方都找不到它,我觉得我要发疯了。我认为另一种选择可能是基类有一个微不足道的析构函数,但根据,情况并非如此。即使这种情况下不会出现内存泄漏,但这似乎仍然是未定义的行为 其他人知道另一个案例是什么吗?或者你能肯定地告诉我是我梦见的吗?也许当继承是私有
Base *base = new Inherited();
delete base;
然而,我确信我至少看到了另一种允许安全继承的可能性。然而,我在任何地方都找不到它,我觉得我要发疯了。我认为另一种选择可能是基类有一个微不足道的析构函数,但根据,情况并非如此。即使这种情况下不会出现内存泄漏,但这似乎仍然是未定义的行为
其他人知道另一个案例是什么吗?或者你能肯定地告诉我是我梦见的吗?也许当继承是私有的时候。在这种情况下,用户无法将
Derived*
转换为Base*
,因此无法尝试通过基类指针删除派生类。当然,您仍然必须注意,在派生的实现中的任何地方都不会这样做,可能是在继承是私有的情况下。在这种情况下,用户无法将Derived*
转换为Base*
,因此无法尝试通过基类指针删除派生类。当然,您仍然必须注意,在派生的的实现中,您不会在任何地方执行此操作,因为您总是可以从类继承。不过,有一些规则需要遵守,例如,如果没有虚拟析构函数,则无法以多态方式调用析构函数。为了避免这种情况,例如,您可以对不打算用作基类的基类使用私有派生,例如,来自STL的容器。您始终可以从类继承。不过,有一些规则需要遵守,例如,如果没有虚拟析构函数,则无法以多态方式调用析构函数。为了避免这种情况,例如,您可以对不打算用作基类的基类使用私有派生,例如来自STL的容器。我想可以举一个涉及shared\u ptr
s的例子,因为最好能显示问题的两面
假设您有一个类B
和一个派生类D
和一个复杂类
让我们在某处定义以下函数:
shared_ptr<B> factory () {
// some complex rules at the very end of which you decide to instantiate class D
return make_shared<D>();
}
所谓的析构函数(假设有人会删除它)将是B
中的一个,这不是您想要的
也就是说,将要从中继承的类的析构函数定义为virtual
是一种好的做法,否则在类定义中放入final
,并停止层次结构
还有很多其他的例子,这不是它工作的唯一例子,但它可以帮助解释它工作的原因。我想一个例子可以是涉及共享的例子,因为它可以很好地展示问题的两面
假设您有一个类B
和一个派生类D
和一个复杂类
让我们在某处定义以下函数:
shared_ptr<B> factory () {
// some complex rules at the very end of which you decide to instantiate class D
return make_shared<D>();
}
所谓的析构函数(假设有人会删除它)将是B
中的一个,这不是您想要的
也就是说,将要从中继承的类的析构函数定义为virtual
是一种好的做法,否则在类定义中放入final
,并停止层次结构
还有很多其他的例子,这不是它工作的唯一情况,但它可以帮助解释它工作的原因。正如其他人提到的,只要您通过类自己的析构函数删除该类,换句话说,您就可以
Inherited *ip = new Inherited();
Base *p = ip;
...
delete ip;
你会没事的。有几种不同的方法可以做到这一点,但你必须非常小心,以确保情况确实如此
但是,基类中有一个空的析构函数[并且继承的类型是立即继承的]只在它真正为空时才起作用,而不仅仅是析构函数的主体有一个{}
。[见下面的编辑2!]
例如,如果您的基类中有一个向量
或std::string
,或任何其他需要销毁的类,那么您将泄漏该类的内容。换句话说,您需要100%确保基类的析构函数为空。我不知道有什么编程方法可以确定这一点(也就是说,除了分析生成的代码之外)
编辑:
还要注意“将来的更改”-例如,在Base
中添加字符串或向量,或者将基类从Base
更改为某个具有析构函数“with content”的自编程序,将破坏“空析构函数”概念
Edit2:
应该注意的是,对于“析构函数为空”,在所有派生类中也必须有真正的空析构函数。有些类没有需要销毁的成员(例如,接口类通常没有数据成员,因此它们本身不需要销毁),因此您可以构造这样的情况,但是,我们必须非常小心地避免派生类的析构函数向类中添加析构函数。正如其他人所提到的,只要您通过类自己的析构函数删除该类,换句话说,您就是这样做的
Inherited *ip = new Inherited();
Base *p = ip;
...
delete ip;
你会没事的。有几种不同的方法可以做到这一点,但你必须非常小心,以确保情况确实如此
但是,基类中有一个空的析构函数[并且继承的类型是立即继承的]只在它真正为空时才起作用,而不仅仅是析构函数的主体有一个{}
。[见下面的编辑2!]
例如,如果basec中有一个向量
或std::string
,或任何其他需要销毁的类