关于在强制转换为子类的超类时调用其重写方法
About calling an subclass' overriding method when casted to its superclass
#include <iostream>
class Vehicle {
public:
void greet() {
std::cout << "Hello, I'm a vehicle";
}
};
class Car : public Vehicle {
public:
void greet() {
std::cout << "Hello, I'm a car";
}
};
class Bike : public Vehicle {
public:
void greet() {
std::cout << "Hello, I'm a bike";
}
};
void receiveVehicle(Vehicle vehicle) {
vehicle.greet();
}
int main() {
receiveVehicle(Car());
return 0;
}
如您所见,我正在尝试将 Vehicle
类型的参数发送到调用 greet()
的函数。
Car
和 Bike
是 Vehicle
的子类。他们覆盖greet()
.
但是,我得到"你好,我是一辆车"。
我想这是因为receiveVehicle
接收Vehicle
类型的参数,而不是像 Car
或 Bike
这样的特定子类。但这就是我想要的:我希望这个函数适用于Vehicle
的任何子类。
为什么我没有得到预期的输出?
您的代码有两个问题:
1) 调用 receiveVehicle(Car());
参数时被值接受。这意味着发生了与切片相关的问题 - 调用Vehicle
的默认复制构造函数,该构造函数从您的汽车构造Vehicle
。更改为指针或引用,使其在缩进时工作。
例如:
void receiveVehicle(Vehicle& vehicle) {
vehicle.greet();
}
int main() {
Car aCar;
receiveVehicle(aCar);
return 0;
}
2) 仅当基方法标有 virtual
关键字时,才会进行多态调用。所以你需要greet
虚拟化:
class Vehicle {
public:
virtual void greet() {
std::cout << "Hello, I'm a vehicle";
}
};
为了严格起见,您还可以根据需要使用const
:
class Vehicle {
public:
virtual void greet() const { //change it also in subclasses
std::cout << "Hello, I'm a vehicle";
}
};
void receiveVehicle(const Vehicle& vehicle) {
vehicle.greet();
}
只有指针和引用可以是多态的。您正在经历切片,其中基类是从派生类构造的,并失去其作为派生和所有额外数据成员的标识。
tl;dr:更改您的函数以接受Vehicle&
(并使参数成为非临时参数),它将正常工作。此外,默认情况下函数是非虚拟的,因此您需要在基类中的函数定义之前添加单词 virtual
,例如 virtual void greet() { ... }
(感谢 Diego 注意到)。
详细解释:
请记住,当您有一个值时,编译器必须知道要为其分配多少内存。派生类可以大于基类,因此当您从派生类构造基类时,它会丢失(切片)派生类携带的数据,并且仅保留基类数据。
即使派生类没有成员,因此不大于基类,编译器也知道值不能是多态的,因此它不必费心从实例的 vtable 中查找虚函数。它只会直接调用函数,导致静态(非多态)行为,并调用基类函数。
想想如果编译器确实调用了虚拟的,会发生什么:
this
指针将指向一个没有派生数据的对象,因为它被切掉了,当函数尝试访问派生成员变量时,它们将不存在!
void receiveVehicle(const Vehicle &vehicle) {
vehicle.greet();
}
// Make your `greet` method `const`
通过引用(或指针,如果您知道风险)传递它,让多态性起作用。否则Car
将被切片成Vehicle
。
- 在从给定超类继承的所有类上调用虚函数
- 按值将对象传递给 SubClass 构造函数,导致超类的构造函数不调用
- 将 void* 强制转换为多个继承类的超类不会调用正确的方法
- 我可以从我的超类调用子类构造函数吗?
- C++ 如何使用一个参数从派生类构造函数中调用具有两个参数的超类构造函数
- 如何在 c++ 中从模板基类的构造函数调用模板超类的构造函数?
- 子类/超类的"无匹配函数调用"
- 从构造函数的主体调用超类构造函数
- 调用超类函数继承 c++
- C ++如何使用子类调用函数,具有超类指针
- 在子类的构造函数中调用超类的构造器两次
- 超类和子类,不同的函数调用取决于子类
- 调用子重写时,始终调用超类虚拟函数
- C++调用同一虚拟函数的超类函数
- C++调用模板化超类的继承方法
- 从超类调用子类的方法
- 为什么超类 B 调用子类 A 的方法?
- 超类调用子类方法的STL迭代器
- 从vector的超类调用子类方法
- 从超类调用子类方法