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

时间:2016-04-30 20:35:32

标签: c++ inheritance polymorphism

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

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

这是我的代码:

Vehicle.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();
};

Vehicle.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;
}

1 个答案:

答案 0 :(得分:1)

根据您的课程,每个Bike和每Car Vehicules. 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();
}

这假设要将add的签名更改为:

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

这是 live demo

和解决方案

如果你有多态类,那么不能从多态中受益是一个小小的问题:

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

重新设计的功能的实现:

var SleepyBand_TaskName = "DataHandlerTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
    if (task.Value.Name == SleepyBand_TaskName)
    {
        task.Value.Unregister(true);
    }
}
var builder = new BackgroundTaskBuilder();
var trigger = new TimeTrigger(16, false);
builder.Name = SleepyBand_TaskName;
builder.TaskEntryPoint = "SleepyBand_BackgroundTasks.DataHandlerTask";
builder.SetTrigger(trigger);
builder.Register();

无论您从车辆中获得多少课程,这都将有效!不再需要添加几十个相同功能的类似重载。

Online demo