关于调用子类'转换为超类时的重写方法

时间:2013-10-20 21:45:48

标签: c++ inheritance

#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()的函数。

CarBikeVehicle的子类。它们会覆盖greet()

然而,我得到“你好,我是一辆车”。

我认为这是因为receiveVehicle收到类型为Vehicle的参数,而不是CarBike等特定子类。但这就是我想要的:我希望这个函数能够与Vehicle的任何子类一起使用。

为什么我没有得到预期的输出?

3 个答案:

答案 0 :(得分:4)

只有指针和引用可以是多态的。您正在经历切片,其中基类是从派生类构造的,并且作为派生类和所有额外数据成员失去其身份。

tl; dr :更改您的函数以接受Vehicle&(并使参数成为非临时参数),它将正常工作。此外,默认情况下,函数是非虚函数,因此您需要在基类中的函数定义之前添加单词virtual,例如virtual void greet() { ... }(感谢Diego注意)。

  

长解释

     

请记住,当您有值时,编译器必须知道要为其分配多少内存。派生类可以比基类大,因此当您从派生类构造基类时,它会丢失(切掉)派生类所携带的数据,并且只保留基类数据。

     

即使你的派生类没有成员,因此不比基类大,编译器也知道一个值不能是多态的,所以它不会费心从vtable中查找虚函数。实例。它只是直接调用函数,导致静态(非多态)行为,并调用基类函数。

     

想想如果编译器调用虚拟文件会发生什么:this指针会指向一个没有派生数据的对象,因为它被切掉了,当函数尝试时要访问派生成员变量,它们就不会存在!

答案 1 :(得分:4)

您的代码存在两个问题:

1)当您致电receiveVehicle(Car());时,参数会被值接受。这意味着发生了与slicing相关的问题 - 调用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();
}

答案 2 :(得分:1)

void receiveVehicle(const Vehicle &vehicle) {
    vehicle.greet();
}
// Make your `greet` method `const`

通过引用(或指针,如果你知道风险)来传递它让多态性起作用。否则,Car将被切分为Vehicle