为什么我不能对正态变量进行多态性?
Why can't I do polymorphism with normal variables?
我是一名Java程序员,最近开始学习C++。我被什么事弄糊涂了。
我知道在C++中,要实现多态行为,必须使用指针或引用。例如,考虑具有已实现方法getArea()
的类Shape
。它有几个子类,每个子类都以不同的方式覆盖getArea()。然后考虑以下功能:
void printArea(Shape* shape){
cout << shape->getArea();
}
该函数根据指针指向的具体Shape
调用正确的getArea()
实现。
这是一样的:
void printArea(Shape& shape){
cout << shape.getArea();
}
然而,以下方法在多态性上不起作用:
void printArea(Shape shape){
cout << shape.getArea();
}
无论函数中传递了哪种具体类型的Shape
,都会调用相同的getArea()
实现:Shape
中的默认实现。
我想了解这背后的技术原因。为什么多态性适用于指针和引用,而不适用于正常变量?(我想这不仅适用于函数参数,也适用于任何情况)。
请解释这种行为的技术原因,以帮助我理解。
答案是复制语义。
当你在C++中按值传递对象时,例如printArea(Shape shape)
,你传递的对象会有一个副本。如果你把一个派生类传递给这个函数,那么所有被复制的都是基类Shape
。如果你仔细想想,编译器不可能做任何其他事情。
Shape shapeCopy = circle;
shapeCopy
被声明为Shape
,而不是Circle
,所以编译器所能做的就是构造对象的Shape
部分的副本。
调用void printArea(Shape shape)
时,对象会复制到堆栈上的全新Shape
中。子类部分不会被复制。这就是所谓的对象切片。如果基类对象是不合法的(例如,它有纯虚拟函数),你甚至不能声明或调用这个函数。这就是"传递值"语义;将提供传入对象的副本。
调用void printArea(Shape& shape)
时,会传递对Circle
或Rectangle
对象的引用。(具体来说,是对该对象的Shape
部分的引用。如果不强制转换,就无法访问特定于Circle
或Square
的成员。但虚拟函数当然可以正常工作。)这就是"通过引用传递"语义;传入对原始对象的引用。
您正在讨论运行时多态性。
这是一个对象可以是从*静态已知类派生的类的想法,因此对静态已知类中的虚拟成员函数的调用最终会出现在派生类实现中。
有了指针或引用,派生程度最高的类可以不同于(比)静态已知的类。但对于直接变量,静态已知的类是派生最多的类。因此,除了最终导致基类成员函数调用的调用之外,没有运行时多态性的空间(在基类成员函数中,静态已知的类型是该基类,与大多数派生类不同)。
*)静态已知类意味着编译器在没有任何分析的情况下已知,即声明的类
基本上,当您按值传递对象时,它会被复制到目标类型的对象-在这一点上,它是目标类型的对象,所以没有什么可以多态的(这甚至是一个词吗?)。
使用您的示例void printArea(Shape shape);
,在printArea()
函数内,参数shape
是Shape
对象,而与调用站点使用的对象无关。
- 多态性和功能结合
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- C++boost序列化多态性问题
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何在多线程中正确使用unique_ptr进行多态性?
- 具有智能指针的多态性
- 在 C++ 中在堆栈上创建实例时如何保持多态性?
- 继承/多态性 - 我是否被迫使用"protected"变量?
- C++ 多态性在代码::块 17.12 中不起作用
- C++ 泛型和多态性:这种模式可行吗?
- 为什么我们实际上需要运行时多态性?
- 如何在这个简单的最小示例中实现多态性?
- 成员变量多态性
- 具有引用成员变量的多态性
- 涉及指针成员变量和多态性的非常奇怪的问题
- 静态成员变量在C++中如何与多态性一起表现
- 为什么我不能对正态变量进行多态性?
- 如何找出变量的类型,包括继承/多态性
- 成员变量多态性和参数引用