C++ 从接口(interface)类到子类的无效转换

标签 c++ inheritance polymorphism

我正在尝试解决这个问题,但我不知道如何从接口(interface)类转换为我的子类。基本上,我试图将车辆指针数组和数组元素作为子类指针,然后将元素逐个传递给 Counter 类方法,该方法将计算总乘客的值,但我收到编译器错误:

invalid conversion from 'oss:Vehicle*' to 'oss::Bike*' [-fPermissive]

这是我的代码:

车辆.h

using namespace std;

namespace oss{

class Vehicle
{
public:
    virtual string type() = 0;
    virtual unsigned passengers() = 0;
    virtual ~Vehicle();
};

class Land_vehicle : public Vehicle{
protected:
    string typeOfVehicle;
    unsigned numberOfPassengers;
public:
    Land_vehicle();
    string type();
};

class Bike : public Land_vehicle{
public:
    Bike();
    unsigned passengers();
};

class Counter{
private:
    int totalPassengers;
public:
    Counter();
    void add(Bike*b);
    int total();
};

车辆.cpp

using namespace oss;

Vehicle::~Vehicle(){};

Land_vehicle::Land_vehicle(){typeOfVehicle = "Land";}
string Land_vehicle::type(){return typeOfVehicle;}

Bike::Bike(){numberOfPassengers = 1;}
unsigned Bike::passengers(){return numberOfPassengers;}

Counter::Counter(){totalPassengers = 0;}

void Counter::add(Bike b){
    cout <<"inside add bike"<<endl;
    totalPassengers += b.passengers();
}
int Counter::total(){return totalPassengers;}

main.cpp

using namespace std;
using namespace oss;

int main()
{
    Counter c;
    Vehicle* v[] = {new Bike};

    size_t sz = sizeof v/sizeof v[0];
    for (unsigned i = 0; i < sz; ++i)
        c.add(v[i]);

    std::cout << "Total: " << c.total() << " passengers!" << std::endl;

    for (unsigned i = 0; i < sz; ++i)
        delete v[i];

    return 0;
}

最佳答案

根据您的类(class),每Bike以及每个CarVehicules. THis is why, whenever you need a 车辆* , you can use as well a 自行车* or a汽车*`。

您在作业中使用了这一点:

Vehicle* v[] = {new Bike};   // yes a Bike* can be converted to a Vehicle*

然而,相反的关系并不成立。不是每个Vehicle是必要的Bike 。这就是为什么你不能只使用 Vehicle*当您需要Bike*时。要执行相反的条件,您首先必须检查Vehicle您正在使用的确实是 Bike ,如果是这种情况,您可以使用强制转换。

幸运的是,您的类是多态的(由于虚函数)。所以你必须使用 dynamic_cast()从父(基)指针转换为子(派生)指针。但请注意检查转换是否成功(即强制转换的指针不为空)。

这里出了什么问题?

当您尝试将车辆添加到柜台时,您会遇到此问题及相关问题:

    c.add(v[i]);   // v[i] is a pointer to a vehicle, but which one

事实上,您的 Counter::add() 有几个问题:

  • 首先,您有一个普通对象作为参数,而不是指针。这意味着您需要使用 c.add(*v[i]) 取消引用指针。 。但是重载要求您在编译时告知它是哪种类型的对象(即没有 add(Vehicle) ,如果有的话,您就会遭受对象切片的困扰)
  • 然后,如果您使用指针而不是普通对象,则可以使用强制转换: c.add(dynamic_cast<Bike*>(v[i]);
  • 最后,您会意识到,即使使用类型转换,您也会遇到问题:在您的示例中,您发誓阵列中只有一辆自行车。但在实际代码中,您现在无法确定。

第一个解决办法

现在将它们放在一起,以下是如何修改循环以仅将自行车添加到计数器:

for (unsigned i = 0; i < sz; ++i) {
    if (dynamic_cast<Bike*>(v[i]))
        c.add(dynamic_cast<Bike*>(v[i]));
}

这应该更改添加的签名:

void Counter::add(Bike* b){
    cout <<"inside add bike"<<endl;
    totalPassengers += b->passengers();
}

这里有一个 live demo

以及解决方案

如果你有多态类,不从多态性中受益是很遗憾的:

class Counter {
    int totalPassengers;
public:
    Counter();
    void add(Vehicle* b);
    int total();
};

以及重新设计的功能的实现:

void Counter::add(Vehicle* b){
    totalPassengers += b->passengers();
}

无论您从车辆派生多少类,这都将起作用!不再需要添加同一函数的数十个类似重载。

Online demo

关于C++ 从接口(interface)类到子类的无效转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36959972/

相关文章:

c++ - 能够将子类实例分配给堆栈框架中的基类变量的动机是什么?

java - 如何在 python 交易模型中创建运行时间条件?

c++ - 如何使用 CUDA 生成随机排列

c++ - 如何使继承的基类使用公共(public)变量

inheritance - Rails : ActiveRecord's default_scope and class inheritance

mysql - 类多态 SQL 数据库表结构

c++ - 检查 ofstream 是否为空?

c++ - 错误 : "expected a type specifier"

c++ - 检查类是否继承自模板的任何模板实例化

c++ - 将方法参数类型更改为子类中的派生类