【发布时间】:2013-12-18 03:17:47
【问题描述】:
我需要编写一个可供新手和有经验的 C++ 开发人员使用的编码约定。动态多态的继承规则是这样的:
- 对于动态多态性,考虑使用单继承(树状层次结构),可能使用抽象接口的多继承
- 对于沿层次结构(基类等)的继承,默认情况下,使用公共继承
- 对于抽象接口的继承,默认,使用公共虚拟继承
此规则后面将提供有关实施、可能的例外情况等的详细信息。
那么,问题是:这个规则对新手和有经验的 C++ 开发人员都适用吗?(欢迎提供优点/缺点以及来源和链接)
我看到的是:
优点:
- 规则易于新手使用,不限制有经验的开发人员。
- 熟悉那些已经熟悉 Java/.NET 接口的人
- 避开了与实现的虚拟继承相关的问题(因为它是为抽象接口保留的)以及非虚拟继承(转换为接口类时可能存在歧义)
缺点:
- 轻微的性能成本(转换到接口时的速度、虚拟表的大小、类实例中的附加指针)
注意:我已阅读以下在线资源:
- When virtual inheritance IS a good design?
- http://www.parashift.com/c++-faq-lite/virtual-inheritance-abcs.html
- http://www.artima.com/intv/abcs.html
- http://cpptips.com/virt_inher2
- http://g.oswego.edu/dl/mood/C++AsIDL.html
注 2:“抽象接口”名称的使用是在 Sutter 和 Alexandrescu 在“C++ 编码标准”第 36 条中使用之后创造的
这是一种应该可以工作的情况(使用接口的 Java/C# 等价物也可以工作),但如果接口继承不是虚拟的,则在 C++ 中就不行:
class A
{
public :
virtual ~A() = 0 {}
} ;
class B : public A {} ; // should have been virtual to avoid the error
class C : public A {} ; // should have been virtual to avoid the error
class D : public B, public C
{
public :
virtual ~D() {}
} ;
void foo(A * c) {}
void bar(D * d)
{
foo(d) ; // Error: ambiguous conversions from 'D *' to 'A *
}
是的,为了消除歧义而进行显式转换是错误的解决方案(无论如何,显式转换通常是错误的解决方案)。
【问题讨论】:
-
对我来说似乎很好。我还要添加一条规则:“尽可能避免 OO 多态性。尝试使用 CRTP 和 ad-hoc polymorphism using type-erasure 等替代方法”
-
我想说实现继承通常应该是私有的(仅在必要时公开成员),并且只有在有充分理由不喜欢组合时才这样做。接口继承通常应该是非虚拟的,因为派生类通常是最终的。一般来说,让继承尽可能简单(但不要更简单)。
-
@user3034482 :比较基类指针?做什么的?我从来没有在我的问题中提到过,是吗?无论如何,你还在为微优化而战吗?当您的结构为 500 字节或更大时,一个指针的性能损失是多少?一个虚函数调用在进行可能跨越 1 毫秒或更长时间的冗长排序时对性能有何影响?禁用 RTTI 或异常?拜托,我们是在 2013 年,而不是 1990 年......如果我想要性能,我会删除所有 qsort 调用并 void * 污染代码,然后用 std::sort 和仿函数替换。这不是重点。
-
@user3034482:
please look at the Google C++ style guide:我做到了。事实上,StackOverflow 的很多 Top 1% 的人都这样做了,而他们的 cmets 对此并不十分积极。 “Google C++ Style reference”并不是真正的 C++ 参考,而更像是“如果您是新手,不想学习,请使用该子集,谢谢”。如果您需要 C++ 的参考资料,请使用严肃的文档,例如 Sutter 和 Alexandrescu 的 C++ 编码标准,或查看 F-35 “JSF C++ 编码标准”。 -
@user3034482:
they don't do rtti and exceptions; its for good reasons。对于RTTI(规则是“避免”,没有提到效率,只有设计)。至于异常,这是基于 Google 的代码不是异常安全的事实做出的决定,这是一种礼貌的说法,它很容易泄漏内存和资源,因此比其他任何东西都更能证明代码的状态。同样,几乎没有提到效率。
标签: c++ oop inheritance multiple-inheritance