Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.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+;中的基类继承+;_C++_Inheritance - Fatal编程技术网

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
,或任何其他需要销毁的类