我正在阅读迈耶斯的“更有效的 C++ 35 种新方法”- 第 33 项,他在那里建议 始终继承自抽象基类,而不是具体基类。
他声称的一个原因(我不太明白)是从抽象类继承时,以多态方式处理数组(书中的第 3 项)不是问题。
有人可以建议这是怎么回事吗?
此外,我想知道永远不要让客户实例化其他派生的类是否真的总是一件好事? (例如,迈耶斯在他的书中展示了赋值运算符的问题)
请求的代码示例:
类 BST {.... };
CLASS BlanacedBST::公共(public) BST {....}
void printBSTArray(ostream& s, const BST 数组[],int Numelements) { for(int i=0;i < Numelements;i++) { s << 数组[i]; }
BST BSTArray[10]; printBSTArray(BSTArray);//工作正常
BlanacedBST bBSTArray[10]; printBSTArray(bBSTArray);//未定义行为(因为下标运算符根据 BST block 大小推进指针)
然后,他补充说,避免从另一个具体类 (BST) 继承的具体类 (BlanacedBST) 通常可以避免这个问题——我不明白这是怎么回事。
最佳答案
虽然我认为避免从非抽象类继承是一个很好的设计指南并且应该让您对您的设计三思而后行,但我绝对不认为它属于“永远不要这样做”的范畴。
我要说的是,由于切片问题,设计为从中继承数据的类可能应该隐藏它们的赋值运算符。
我认为有一种方法可以对不常被想到的类进行分类,而且我认为这会引起很多困惑。我认为有些类被设计为按值使用,而有些类被设计为始终按引用使用(意味着通过引用或指针或类似的东西)。
在大多数面向对象的语言中,用户定义的类只能通过引用使用,并且有一种特殊的“原始”类型类可以通过值使用。 C++ 的一大优势是您可以创建可按值使用的用户定义类。这可以带来巨大的效率提升。例如,在 Java 中,您的所有点(选择一个随机的简单类)都是堆分配的并且需要进行垃圾收集,即使它们基本上只是两个或三个 double 结合在一起并带有一些不错的“最终”支持功能。
因此,设计为通过引用使用的类应该禁用赋值,并且应该认真考虑禁用复制构造,并要求人们为此目的使用“制作此拷贝”虚函数。请注意,Java 类通常没有赋值运算符或标准复制构造函数之类的东西。
设计为按值使用的类通常不应具有虚函数,尽管让它们成为继承层次结构的一部分可能非常有用。它们仍然可能相当复杂,因为它们可以包含对设计为通过引用使用的类的对象的引用。
如果您需要将按引用类视为按值使用,您应该使用句柄/主体设计模式或智能指针。 STL 容器都是为值对象而设计的,所以这是一个相当普遍的问题。
关于c++ - 抽象类和多态地使用数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1893688/