我回到一个关于dynamic_cast的问题上看了一个答案。 dynamic_cast失败,因为基类没有虚拟方法。其中一个答案表示,从没有虚拟方法的类派生通常意味着一个糟糕的设计。它是否正确?即使没有利用多态性,我仍然看不到这样做的错误。从没有虚拟方法的基类继承不良习惯?
回答
这取决于我们在谈论:
- 的性状类(无数据),它的罚款(
std::unary_function
想到) - 为
private
继承(用于替代组合物从空基地中受益优化)也没关系
当你开始在这个基类中多态地处理这样一个Derived对象时,问题出现了。如果你曾经获得这样的位置,那么它的确是代码异味。
注意:即使在上面提到的罚款时,您仍然提供使用类多态的能力,并且您因此暴露自己以微妙的错误。
C++中没有虚拟方法的继承只不过是代码重用。 我想不到没有多态性的遗传。
为了重用代码,从类派生始终是一个有效的选项。
有时,我们并没有寻找多态行为。没关系 - 我们有这个选择是有原因的。但是,如果是这种情况,那就考虑使用私有继承 - 如果你的类不是多态的,那么任何人都没有理由尝试多态使用它。
我会*不*使用继承*只是*用于代码重用。使我们更好*更好*适合任务,并且使用继承将你更强烈地绑定到基类上,并且让你知道微妙的(转换/隐藏)错误。 –
@Matthieu:一个有效的论点,但仍然有争议。诚然,它肯定需要关注,以及对用户的责任。我会同意组成通常更好,但私人继承仍然是一种替代方案(尽管如此,使用起来更加棘手)。 –
我发现私有继承在两种情况下可行的:作为优化(EBO)或重写虚拟方法(这里不关心)。所有其他人都是懒惰/方便的事情。我有没有提到我对继承/组合辩论相当紧张? –
这里是一个不错的例子,来因素的行为纳入政策(注意保护析构函数):
struct some_policy
{
// Some non-virtual interface here
protected:
~some_policy() { ... }
private:
// Some state here
};
struct some_class : some_policy, some_other_policy { ... };
另一个好例子,以避免在模板代码膨胀。请注意受保护的析构函数:
struct base_vector
{
// Put everything which doesn't depend
// on a template parameter here
protected:
~base_vector() { ... }
};
template <typename T>
struct vector : base_vector
{ ... };
另一个示例,称为CRTP。请注意受保护的析构函数:
template <typename Base>
struct some_concept
{
void do_something { static_cast<Base*>(this)->do_some_other_thing(); }
protected:
~some_concept() { ... }
};
struct some_class : some_concept<some_class> { ... };
另一个示例,称为空基优化。本身并不是真正的继承,因为允许编译器为基类(其充当私有成员)在some_class
中保留空间是更为诡计的技巧。
template <typename T>
struct some_state_which_can_be_empty { ... };
template <typename T>
struct some_class : private some_state_which_can_be_empty<T> { ... };
作为一个经验法则,您继承的类应该具有虚拟或受保护的析构函数。
我找到关于“公共”继承的。 –
@Alexandre C:无论是政策和代码膨胀示例(只要不是必需EBO)可以使用组合物来代替。 CRTP示例是非常特殊的,因为它不允许传统意义上的多态(基类取决于派生类)。 –
@Matthieu:代码膨胀和策略示例通常有一些不平凡的公共接口。如果你让他们成为会员,那么你必须手工编写包装。泛型代码和C++ 03中的繁琐(使用C++ 0x和完美的转发更容易)。 –
C++标准库中的某些类具有受保护的成员(仅对派生类有意义),但没有虚拟成员函数。即,它们被设计用于派生,而不具有虚拟。这证明,从一个没有虚拟的类派生出来的设计通常是不好的设计。
干杯& hth。,
- 1. 从基类虚拟继承
- 2. 习惯从类型继承元类吗?
- 3. 多重继承,虚拟方法碰撞和指针从基类
- 4. 非虚拟接口习惯用于两级以上的继承?
- 5. 从非虚拟父类虚拟类继承的正确方式
- 6. 继承和虚拟方法
- 7. C#中虚拟基类方法/成员的属性继承
- 8. 从继承子类对象访问父类虚拟方法
- 9. 从没有虚拟析构函数的类继承
- 10. 好习惯?虚拟对象
- 11. 虚拟类和继承
- 12. 继承虚拟类和非虚类
- 13. 虚拟继承
- 14. 虚拟继承
- 15. 虚拟继承
- 16. 虚拟方法和多重继承
- 17. 有没有在Django模型中模拟虚拟继承的理智方法?
- 18. 虚基类和继承
- 19. 虚拟继承和在基类空的虚函数表
- 20. 循环类引用不良习惯?
- 21. C++解决菱形继承如果没有虚拟继承
- 22. 找不到方法:模板,虚拟方法,继承,多态
- 23. 从基类C++调用虚拟方法
- 24. 关于虚基类和虚拟继承在C++
- 25. 正确的方式从具有非虚拟父项的虚拟课堂继承
- 26. C++ - 虚拟继承
- 27. C++:虚拟继承
- 28. 多虚拟继承
- 29. 必须实现继承的母类虚拟方法
- 30. 不能从基类继承
关于多态的使用是可能好一点 - 不过,如果你的类定义正确为您介绍了,用户有责任不去加倍努力,以规避这一点。 –
@Ken:问题在于这种责任。即使意想不到,用户可能会弄乱并且多态地使用这个类。当然,这两种情况都不太可能。在前者中,因为特征不具有非静态方法,所以它是无用的,而在后者中,“私人”将错误可能性限制在班级和朋友的方法中。尽管如此,它可能会发生。问题(大部分)是一个缺失的特性:我们希望*代表团*在这里,而不是*继承*。 –