我阅读了继承和多态性,但我仍然无法区分它们之间的区别。
据我所知,继承是例如(从基类和方法覆盖的派生类继承方法也可以执行。)那么什么是多态性?继承和多态在某种程度上都有意义吗?
请纠正我,因为我知道我错了。谢谢
我阅读了继承和多态性,但我仍然无法区分它们之间的区别。
据我所知,继承是例如(从基类和方法覆盖的派生类继承方法也可以执行。)那么什么是多态性?继承和多态在某种程度上都有意义吗?
请纠正我,因为我知道我错了。谢谢
多态性允许您在其继承的父类之间来回变形类。以下是合法的,如果 Dog 和 Cat 类继承自 Animal
void takes_animal(Animal &animal) { }
Dog dog;
Cat cat;
takes_animal(dog);
takes_animal(cat);
用农夫的话来说,多态性是指您使用“基”类(在某些情况下称为接口)而不知道实际实现的真正含义。继承可以与多态一起使用,也可以不与多态一起使用(即,当您使用继承但始终知道您正在处理的对象的特定类时,即使它是从其他东西继承的,也不是多态)。但是没有继承就不能使用多态性(它只是没有任何意义)。
继承是一种实现技术。多态性是您可以用它实现的事物之一的一个方面。(这不是唯一的事情。例如,继承自
std::iterator
与多态无关。)
在这种情况下,我们有继承但没有多态性:
struct SimpleBase {
int i;
int get() const { return i; }
};
struct SimpleDerived: public SimpleBase {
int get() const { return i + 7; }
};
SimpleBase 的一个实例(或指向它的引用或指针)总是如此,派生类不能改变它的行为。例如:
int foo(SimpleBase const &obj) { return obj.get(); }
将始终调用SimpleBase::get
,即使我传入派生类型的实例。
相反,通过多态性,派生类可以用自己的版本覆盖基类方法:
struct PolyBase {
int i;
virtual int get() const { return i; }
};
struct PolyDerived {
int get() const { return i + 7; }
};
int foo(PolyBase const &obj) { return obj.get(); }
现在 foo 根据传入的派生类型调用不同的方法,而不知道它是哪个派生类型。
因此,使用多态性,整个类型家族可以共享一个公共接口,并且您可以编写一次对接口进行操作的代码,而无需了解所有不同的派生类型。
上面显示的多态形式是运行时多态:它生成的代码确定每个虚函数在运行时要调用的实现。
还有编译类型的多态,它根本不需要继承,而是使用模板。
假设您想编写一个排序容器(如 std::map) - 您不想将其限制为存储特定的数据类型,但您确实需要一些方法来比较两个元素以查看哪个更大。
运行时方法可能会提供一个抽象基类,例如
struct LessThanComparable {
virtual bool operator< (LessThanComparable const &) const = 0;
};
并要求您要放入容器中的每种类型,都可以从中派生并实现operator<
. 然后,您可以if (a < b)
在您的容器代码中编写代码,您所存储的类型的正确函数将被调用 (*)。
// requires inheritance from abstract base class,
// uses virtual call to operator<
bool less_than(LessThanComparable const &a, LessThanComparable const &b) {
return a < b;
}
STL中实际使用的编译类型方法 (**) 是通过提供合适的operator<
. 但是,这是在编译时解决的,不需要公共基类。
// doesn't require any inheritance, doesn't use virtual function call,
template <typename T>
bool less_than(T const &a, T const &b) { return a < b; }
(*) 另请注意,实现operator<
并非易事,因为a < b
可以在a和b具有不同的派生类型时调用。在模板版本中,我们知道它们都具有相同的类型T。
(**) 好的,所以默认std::less
有 LessThanComparable 要求,或者您可以提供替代的 StrictWeakOrdering。
您对继承的看法是正确的,但并不是那么简单。重载和覆盖也是继承的重要功能。而多态性是关于创建多态数组,例如如果父类是水果而苹果是对象,那么您可以将对象定义为水果的类型并调用通用函数。同样创建纯虚函数将阻止父类使其成为实例。