微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

多态是实现这一目标的最佳方式吗? 关于派生类中的函数调用

如何解决多态是实现这一目标的最佳方式吗? 关于派生类中的函数调用

我有一个包含四个类的程序:

  • 车辆(底座)
  • 汽车(源自车辆)
  • 汽车(源自汽车)
  • 卡车(源自汽车)

在运行时,用户使用工厂函数生成一个汽车对象,它是“汽车”或“卡车”:

Automobile *Automobile::make_automobile(std::string choice) {
    if (choice == "car")
        return new Car;
    else if (choice == "truck")
        return new Truck;
    else
        return nullptr;
}

现在,“Car”类具有三个唯一的 setter(和三个匹配的 getter):

  • Set_NumDoors()
  • Set_SeatMaterial()
  • Set_Shape()

“Truck”类有一个唯一的 setter(和一个匹配的 getter):

  • Set_CargoWeight()

起初,这些函数只在它们自己的类中实现,但我无法在运行时调用它们,因为创建的对象是“汽车”对象。我已经使用具有本地覆盖的虚拟函数解决了这个问题。所以现在,“Automobile”类所有四个函数(以虚拟形式),认情况下什么都不做。但是,当在对象上调用时,本地覆盖执行正确的功能。下面是一个例子,一切正常。

汽车类的定义

std::string defaultStatement = "Function call is invalid on current object";
    virtual int set_seatMaterial(std::string choice){
        std::cout << defaultStatement << std::endl;
        return -1;
    }

在 Car 类中覆盖

    int set_seatMaterial(std::string choice) override { // override virtual base
        if (choice == "leather" || choice == "cloth"){
            seatMaterial = choice;
            return 0;
        }
        else
            return -1;
    }

然后我在 main() 中使用函数指针来适当地指向所需的函数

if (user_choice == "seat"){
            std::function<int(Automobile*,std::string)> choiceFunction = &Automobile::set_seatMaterial;
            choiceFunction(userVehicle,seatMaterial);
}

我唯一的问题是 - 这是实现此功能的最佳方式吗?它可以工作,但现在我已经声明了“汽车”类中的每个函数,该类已经有自己的 getter/setter。虽然我理解多态的概念和它的用处,但从某种意义上说,这似乎是重复。

或者有更好的方法从基类对象调用派生类函数吗?

解决方法

我已经使用具有本地覆盖的虚函数解决了这个问题。所以现在,“Automobile”类所有四个函数(以虚拟形式),默认情况下什么都不做。但是,当在对象上调用时,本地覆盖执行正确的功能。下面是一个例子,一切正常。

这使得 Automobile 的实现者必须知道所有继承自它的类提供的所有方法,这使得维护变得困难。

另一种选择是在您需要知道您正在处理的 dynamic_cast 类型的情况下使用 Automobile

C++11 示例:

Automobile* unknown = ...;

if(auto car = dynamic_cast<Car*>(unknown)) {
    // call car-specific methods
    car->Set_NumDoors(4);

} else if(auto truck = dynamic_cast<Truck*>(unknown)) {
    // call truck-specific methods
    truck->Set_CargoWeight(1000);
}

Demo

,

您的问题确实涉及一个主要的设计问题。一般来说,如果对象通常可以被相同地对待,则多态性是最合适的。只有在少数特定情况下才需要知道对象的确切类型。换句话说,在您的示例中,所有汽车都有一个重要的共同行为子集,而且大多数时候我们甚至不想知道我们在这里拥有哪种汽车。如果您发现自己一遍又一遍地对 Ted 的 if-else 链进行编程,则可能表明这些工具的不同足以保证单独处理。如果您发现确实如此,例如,您将没有指向汽车的指针向量,而是将卡车、汽车和半成品的向量分开,然后单独处理。

但是让我们假设多态在这里是一种有效的方法,因为每种类型的汽车需要特殊处理的情况只有有限的几种:当你买一辆车时,当你修理一辆车时,当你处理一辆车时。例如,汽车购买者可能想要选择座椅材料,而购买卡车的公司则没有这种选择。显然,在各自的汽车“设置”中,还有更多不同的地方。

这里的解决方案是为每种情况指定一个抽象的汽车基类方法。例如,每辆车都有一个“设置”程序,它与用户交互并获取所需的子类型特定信息。因此,您不再依赖 if-else 链,而是再次依赖多态性来为您做正确的事情。如果您可以将所有不同的行为放入由基类中的抽象方法描述的统一抽象模式中,则此方法有效。缺点是对象可能需要有关其环境的信息(iostream、图形上下文、数据库访问等),而这些信息与它们的实际功能无关。为了弱组件耦合,我们主要希望将这些东西与汽车分开。因此,在这里,如果对象足够相似以至于它们需要一组相似的信息,这些信息可以传递给公共方法(而不是被相应的汽车对象知道),那么这种方法也是最有效的。

作为结论,这里有一个一般的经验法则:虽然 Ted 的回答没有错,但人们应该始终怀疑动态转换和 if-else 链;它们通常是缺乏抽象的标志。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。