【问题标题】:Virtual method overrides in C++C++ 中的虚方法重写
【发布时间】:2016-04-21 18:18:08
【问题描述】:

假设我们有一个名为 Vehicle 的抽象类:

class Vehicle {
    virtual bool raceWith(Vehicle *anotherVehicle) = 0;
};

我们有它的子类BicycleCar

//  forward declaration
class Car;

class Bicycle : public Vehicle {
    virtual bool raceWith(Vehicle *anotherVehicle) {
        throw SomeExceptionClass();
    }

    virtual bool raceWith(Car *anotherVehicle) {
        return true;
    }

    virtual bool raceWith(Bicycle *anotherVehicle) {
        return false;
    }
};

但是,这段代码抛出了 SomeExceptionClass:

Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();

aBicycle->raceWith(aCar);

在这里做什么? C++不允许我们以这种方式使用多态方法吗?

任何帮助将不胜感激。谢谢。

编辑:提供dynamic_cast<>decltype 变体的答案也很好?

【问题讨论】:

    标签: c++ polymorphism virtual-functions dynamic-dispatch


    【解决方案1】:

    以下将与Bicycle 竞争Vehicle

    Vehicle *aBicycle = new Bicycle();
    Vehicle *aCar = new Car();
    
    aBicycle->raceWith(aCar);
    

    要将BicycleCar 竞争,我们需要使用双重调度。

    为了使双重调度工作,我们使用this 指针调用下一个函数,以便第二个虚拟调用可以解析到正确的车辆类型:

    class Car;
    class Bicycle;
    
    class Vehicle {
    public:
        virtual bool raceWith(Vehicle& anotherVehicle) = 0;
        virtual bool raceWith(Bicycle& anotherVehicle) = 0;
        virtual bool raceWith(Car& anotherVehicle) = 0;
    };
    
    
    class Bicycle : public Vehicle {
    public:
        virtual bool raceWith(Vehicle& anotherVehicle) override
        {
            //throw std::exception();
            return anotherVehicle.raceWith(*this);
        }
    
        virtual bool raceWith(Car& anotherVehicle)
        {
            return true;
        }
    
        virtual bool raceWith(Bicycle& anotherVehicle)
        {
            return false;
        }
    };
    
    class Car : public Vehicle {
    public:
        virtual bool raceWith(Vehicle& anotherVehicle) override
        {
            return true;
        }
    
        virtual bool raceWith(Car& anotherVehicle) override
        {
            return true;
        }
    
        virtual bool raceWith(Bicycle& anotherVehicle) override
        {
            return false;
        }
    
    };
    
    int main()
    {
    
        Vehicle *aBicycle = new Bicycle();
        Vehicle  *aCar = new Car();
    
        aBicycle->raceWith(*aCar);
    }
    

    注意return anotherVehicle.raceWith(*this);,它将执行第二个虚拟调用。

    然后按以下顺序调用函数:

    • main();
    • Bicycle::raceWith(Vehicle& anotherVehicle);
    • Car::raceWith(Bicycle& anotherVehicle);

    以下是相同的程序,但坚持使用问题中提供的指针和异常:

    #include <exception>
    
    class Car;
    class Bicycle;
    
    class Vehicle {
    public:
        virtual bool raceWith(Vehicle* anotherVehicle) = 0;
        virtual bool raceWith(Bicycle* bicycle) = 0;
        virtual bool raceWith(Car* car) = 0;
    };
    
    
    class Bicycle : public Vehicle {
    public:
        virtual bool raceWith(Vehicle* anotherVehicle) override
        {
            //throw std::exception();
            return anotherVehicle->raceWith(this);
        }
    
        virtual bool raceWith(Car* car) override
        {
            return true;
        }
    
        virtual bool raceWith(Bicycle* bicycle) override
        {
            return false;
        }
    };
    
    class Car : public Vehicle {
    public:
        virtual bool raceWith(Vehicle* anotherVehicle) override
        {
            throw std::exception();
        }
    
        virtual bool raceWith(Car* car) override
        {
            return true;
        }
    
        virtual bool raceWith(Bicycle* bicycle) override
        {
            return false;
        }
    
    };
    
    int main()
    {
    
        Vehicle *aBicycle = new Bicycle();
        Vehicle  *aCar = new Car();
    
        aBicycle->raceWith(aCar);
    }
    

    【讨论】:

    • 什么是双重调度?
    • @Leviathlon 双重虚拟调度是根据两个对象的动态类型调用正确实现的能力。 C++ 仅在this 上提供单个虚拟调度。 flatmouse 在这里描述的就是访问者模式,通过两次单调度实现双调度。
    • 这解决了问题。这么棒的答案。感谢您的关注。
    【解决方案2】:

    通过做

    Vehicle *aBicycle = new Bicycle();
    aBicycle->raceWith(aCar);
    

    aCar 的类型是 Vehicle (typeid(aCar).name()),因此您的编译器正在使用 Vehicle 调用该方法。

    试试

    aBicycle->raceWith(static_cast<Car*>(aCar));
    aBicycle->raceWith(dynamic_cast<Car*>(aCar));
    

    至于为什么static_cast还是dynamic_cast,可以看SO上的这个帖子:Regular cast vs. static_cast vs. dynamic_cast

    【讨论】:

    • 很抱歉,我错过了。
    • 我说过子类。请不要将此作为答案。
    • 在面向对象编程中它有一个定义。不幸的是,它永远不会有所不同。
    • @Leviathlon 我删除了那部分答案。
    • 还是不行,我发现这个问题只能通过双重动态调度来解决。
    【解决方案3】:

    试试这个,你可以使用动态转换来检测子类的类型。如果您将virtual bool raceWith(Vehicle *anotherVehicle) 保留为方法,则virtual bool raceWith(Car *anotherVehicle)virtual bool raceWith(Bicycle *anotherVehicle) 可能永远不会在没有强制转换的情况下执行,因为anotherVehicle 是Vehicle 类型obj。希望会有所帮助:)

    #include <iostream>
    using namespace std;
    class Car;
    class Bicycle;
    
    class Vehicle {
        public:
         //virtual bool raceWith(Vehicle *anotherVehicle) = 0;
         virtual bool raceWith(Car *anotherVehicle) = 0;
         virtual bool raceWith(Bicycle *anotherVehicle) = 0;
    };
    
    class Bicycle : public Vehicle {
        /*virtual bool raceWith(Vehicle *anotherVehicle) {
            throw SomeExceptionClass();
        }*/
        virtual bool raceWith(Car *anotherVehicle) {
            cout << "will print" << endl;
            return true;
        }
        virtual bool raceWith(Bicycle *anotherVehicle) {
            return false;
        }
    };
    class Car : public Vehicle {
        /*virtual bool raceWith(Vehicle *anotherVehicle) {
            throw SomeExceptionClass();
        }*/
        virtual bool raceWith(Car *anotherVehicle) {
            return true;
        }
    
        virtual bool raceWith(Bicycle *anotherVehicle) {
            return false;
        }
    };
    int main()
    {
        Vehicle *aBicycle = new Bicycle();
        Vehicle *aCar = new Car();
    
        if (dynamic_cast<Bicycle*>(aCar) != NULL) {
            std::cout << "Race with A Bicycle" << std::endl;
            aBicycle->raceWith(static_cast<Bicycle*>(aCar));
        }
        else if (dynamic_cast<Car*>(aCar) != NULL) {
            std::cout << "Race with A Car" << std::endl;
            aBicycle->raceWith(static_cast<Car*>(aCar));
        }
        else {
            //throw SomeExceptionClass();
        }
    
        //aBicycle->raceWith(aCar);
    
        return 0;
    }
    

    【讨论】:

    • 我认为,对于您在这里想要实现的目标,google -Visitor design pattern- 会为您提供更多帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 1970-01-01
    • 2013-05-06
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    相关资源
    最近更新 更多