抽象类的目的不是让开发人员创建基类的对象然后向上转换它,AFAIK。
现在,即使不需要向上转换,并且我仍然使用它,它是否在某种程度上被证明是“不利的”?
更多说明:
来自 C++ 中的思考:
通常在设计中,您希望基类只为其派生类提供一个接口。也就是说,您不希望任何人实际创建基类的对象,而只是向上转换到它以便可以使用它的接口。这是通过使该类抽象来实现的,
通过向上转换,我的意思是:baseClass *obj = new derived ();
抽象类的目的不是让开发人员创建基类的对象然后向上转换它,AFAIK。
现在,即使不需要向上转换,并且我仍然使用它,它是否在某种程度上被证明是“不利的”?
更多说明:
来自 C++ 中的思考:
通常在设计中,您希望基类只为其派生类提供一个接口。也就是说,您不希望任何人实际创建基类的对象,而只是向上转换到它以便可以使用它的接口。这是通过使该类抽象来实现的,
通过向上转换,我的意思是:baseClass *obj = new derived ();
对于非多态类,向上转型可能是不利的。例如:
class Fruit { ... }; // doesn't contain any virtual method
class Apple : public Fruit { ... };
class Blackberry : public Fruit { ... };
把它上载到某个地方,
Fruit *p = new Apple; // oops, information gone
现在,您将永远不会知道(没有任何手动机制) if*p
是 anApple
或 a的实例Blackberry
。
[请注意,dynamic_cast<>
非多态类不允许这样做。]
抽象类用于表达一组(子)类共有的概念,但创建实例并不明智。
考虑一个类Animal
。创建该类的实例是没有意义的,因为没有任何东西只是动物。有鸭子、狗和大象,每一种都是动物的一个子类。通过正式声明类动物,您可以捕捉所有类型动物的相似之处,并通过使其抽象,您可以表示它不能被实例化。
需要向上转换才能在静态类型语言中使用多态性。正如@Jigar Joshi 在评论中指出的那样,这就是Liskov Substituion Principle。
编辑:向上转型并不是不利的。事实上,您应该尽可能使用它,使您的代码依赖于超类(接口)而不是基类(实现)。这使您以后无需更改代码即可切换实现。
向上转型是一种技术工具。
像每个工具一样,正确使用它是有用的,如果使用不一致则危险/不利。
它的好坏取决于您希望代码相对于给定的编程范式有多“纯”。
现在,C++ 不一定是“纯 OOP”,不一定是“纯泛型”,也不一定是“纯函数式”。并且由于 C++ 是一种“实用语言”,因此通常不会有优势迫使它适应“唯一的范式”。
用技术术语来说,唯一可以说的是,
dynamic_cast
(用于向下转换)。static_cast
(向下转换)仍然可用,但没有运行时检查。优点和缺点源于对所有这些点的一致和不一致的使用。不只是与沮丧有关的事情。
一个缺点是派生类中引入的新功能明显丢失:
class A
{
void foo();
}
class B : public A
{
void foo2();
}
A* b = new B;
b->foo2(); //error - no longer visible
我在这里谈论的是非虚函数。
此外,如果您忘记将析构函数设为虚拟,则在通过指向基对象的指针删除派生对象时可能会出现一些内存泄漏。
然而,所有这些都可以通过良好的架构来避免。