简体   繁体   English

虚方法C ++

[英]virtual methods C++

I'm facing the following problem. 我面临以下问题。

I implement parent Class - Vehicle , it has some derived classes, one of them - FastVehicle . 我实现父类 - Vehicle ,它有一些派生类,其中之一 - FastVehicle

In the program I need to store a Vector of Vehicle* pointers. 在程序中我需要存储一个Vector of Vehicle *指针。 the pointers may point to Vehicle objects or to FastVehicle objects as well. 指针也可以指向Vehicle对象或FastVehicle对象。

1) I want to be able to call the method print() for every object in the vector. 1)我希望能够为向量中的每个对象调用方法print() The problem is that in case of FastVehicle I also want to tranfer a parameter to the function, I need to call a function with signature: 问题是,在FastVehicle的情况下我也想将参数传递给函数,我需要调用一个带签名的函数:

void print(int a)

I know a little bit about the virtual function mechanism, but according to my knowledge it works only if both functions have the same signature. 我对虚函数机制有一点了解,但据我所知,只有当两个函数具有相同的签名时才有效。

I would like to hear suggestions, about how to work it out. 我想听听有关如何解决问题的建议。

2) In addition in the derived class FastVehicle has some unique function that it doesn't share with the parent class Vehicle. 2)另外在派生类中, FastVehicle有一些独特的功能,它不与父类Vehicle共享。 It performs a task that should be performed only for FastVehicle objects. 它执行的任务只应对FastVehicle对象执行。 What is the cleanest way to achieve this? 实现这一目标的最简洁方法是什么? I thought maybe to implement "empty" virtual function in the parent class Vehicle and implement the "real" task inside an overriding method of FastVehicle 我想可能在父类Vehicle中实现“空”虚函数并在FastVehicle的重写方法中实现“真实”任务

Maybe someone can suggest a better solution. 也许有人可以提出更好的解决方案。

thanks 谢谢

You can always use a dynamic_cast to cast Vehicle to FastVehicle. 您始终可以使用dynamic_cast将Vehicle转换为FastVehicle。 It returns NULL if Vehicle is not FastVehicle. 如果Vehicle不是FastVehicle,则返回NULL。 It depends on your use situation if you should really do this. 如果您真的应该这样做,这取决于您的使用情况。

for(Vehicle* vehicle : vehicleVector)
{
    FastVehicle* fastVehicle = dynamic_cast<FastVehicle*>(vehicle);

    if(fastVehicle)
    {
        fastVehicle->print(1337);
        fastVehicle->somethingElse();
    }
    else
    {
        vehicle->print();
    }
}

Full example available here: https://ideone.com/69n6Jb 这里有完整的例子: https//ideone.com/69n6Jb

The pragmatic solutions are: 务实的解决方案是:

  1. Pass the int a parameter to the virtual print method but ignore it in Vehicle and only use it in FastVehicle int a参数传递给虚拟print方法但在Vehicle忽略它并仅在FastVehicle使用它

  2. As you suggest, simply add an "empty" virtual function to the base class that is a no-op in Vehicle and is only implemented in FastVehicle 正如您所建议的那样,只需将“空”虚拟函数添加到基类中,该基类是Vehicle的无操作,并且仅在FastVehicle实现

Eg: 例如:

struct Vehicle {
  virtual ~Vehicle(){}
  virtual void print(int /*a*/) const { std::cout << "Vehicle print\n"; }
  virtual void somethingElse() { /* no-op */ }
};

struct FastVehicle : Vehicle {
  void print(int a) const override {std::cout << "FastVehicle print " << a << "\n";}
  void somethingElse() override { std::cout << "Something else!\n"; }
};

for (auto vehicle : vehicles) {
  vehicle->print(512);
  vehicle->somethingElse();
}

Live demo 现场演示

Most likely you have to rethink why you need a parameter for FastVehicle, but not for anything other type of Vehicle. 您很可能需要重新考虑为什么需要FastVehicle的参数,而不是其他任何类型的Vehicle。 That to me is an indication of bad design. 对我而言,这表明设计糟糕。

Just declare print(int) in the base class, override it, but in the classes where you don't need the int, just disregard it. 只需在基类中声明print(int),覆盖它,但在不需要int的类中,只需忽略它。

Perhaps you could refactor with an abstract vehicleI : 也许你可以用抽象的vehicleI重构我:

struct vehicleI {
    ....
    virtual void print(int) = 0;
}

and then your vehicle : 然后你的vehicle

struct vehicle : vehicleI {
    ....
    void print(int i = 0);
}

and your fastVehicle as: 和你的fastVehicle

struct fastvehicle: vehicleI {
    ....
    void print(int);
}

if you want to properly use a dynamic call to a Vehicle interface, you need to define a common interface. 如果要正确使用对Vehicle界面的动态调用,则需要定义公共接口。 If you need to specify a parameter in case of FastVehicle but not in the case of FastVehicle, that's not an interface anymore. 如果你需要在FastVehicle的情况下指定一个参数,而不是在FastVehicle的情况下,那不再是一个接口了。

You have two solutions: 你有两个解决方案:

Default parameter 默认参数

struct Vehicle
{
  virtual void print(int a=0) {};
};

struct FastVehicle : public Vehicle
{
  void print(int a=0) override {};
};

now you can call both with or without a parameter. 现在你可以使用或不使用参数调用它们。

Second option: 第二种选择:

struct Vehicle
{
  virtual void print() {};
};

struct FastVehicle : public Vehicle
{
  void print() override {};
  void setA(int a) { _a = a; }
  _a{};
};

Now you can set your 'a' variable through another method, but not when you access the object through Vehicle's interface. 现在,您可以通过另一种方法设置“a”变量,但不能通过Vehicle的界面访问对象时设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM