如何让派生类使用基类实现来满足接口

How to have a derived class use the base implemention to satisfy an interface

本文关键字:实现 基类 满足 接口 派生      更新时间:2023-10-16

我有以下两个接口,它们不属于继承层次结构。然后我有两个具体的类,其中一个派生于另一个。

class ICar {
    public:
    virtual void drive() = 0;
};
class IFastCar {
    public:
    virtual void drive() = 0;
    virtual void driveFast() = 0;
};
class Car : public virtual ICar {
    public:
    void drive() {};
};
class FastCar : public Car, public virtual IFastCar {
    public:
    void driveFast() {};
};
int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    return 0;
}
当我编译时,我得到以下错误:
error: cannot declare variable `fc' to be of type `FastCar'
error:   because the following virtual functions are abstract:
error:  virtual void IFastCar::drive()

如果我在FastCar中编写一个函数将drive()委托给基类

,我的程序将工作。
void drive() { Car::drive(); }

是可能有FastCar编译没有编写方法委托给基类?

注意:ICar和IFastCar是由两个不同的团队创建的,属于两个不同的项目。团队已经就共享操作的通用方法签名达成一致。我在实现类中使用继承来尝试重用实现中相同的部分。

问题在于这里发生了多重继承…尽管FastCar是从Car派生出来的,但Car基类中的drive()版本只覆盖ICar::drive(),而不是IFastCar::drive()。因此,由于您是从IFastCar派生FastCar,因此需要在某些时候在FastCar中定义一个函数,该函数也覆盖纯虚拟抽象方法IFastCar::drive()…继承的Car::drive()不会自动覆盖IFastCare::drive(),因为它不继承那个类。IFastCar::drive()ICar::drive()是两个不同的纯抽象虚函数,需要分别重写。如果你想让IFastCar::drive()的接口调用你继承的Car::drive()函数,那么你需要委托这个继承的函数,就像你在FastCar::drive()的一个版本中所做的那样,这个版本专门调用drive()的基类版本。

问题是Car不实现IFastCar::drive,而只实现ICar::drive。第一个设计问题是为什么IFastCar不扩展ICar接口并重新定义相同的操作?

如果由于某种原因这不是一个选项,那么你可以做的最简单的事情是通过将请求转发到Car::drive方法来实现FastCar中的IFastCar::drive():

void FastCar::drive() {
   Car::drive();
}

您在这里使用virtual继承是虚假的,并且是转移注意力的。virtual继承仅用于从公共基类派生一次;not只引入一个声明来匹配成员签名。

所以,你的FastCar具体类实际上有3个成员,而不是2个:

virtual void ICar::drive()
virtual void IFastCar::drive()
virtual void IFastCar::driveFast()

两个不同的drive()似乎是相关的,所以你的设计似乎是有缺陷的。您不希望virtual继承—您可能希望IFastCarICar派生。

class ICar {
    public:
    virtual void drive() = 0;
};
class IFastCar : public ICar {
    public:
    virtual void driveFast() = 0;
};
class Car : public virtual ICar {
    public:
    void drive() {};
};
class FastCar : public IFastCar {
    public:
    void drive() {};
    void driveFast() {};
};
int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    return 0;
}

如果您希望Car实现FastCar将采用的一些基本功能,那么您可以从Car派生FastCar,并且就是您希望继承virtual的原因。只要记住在菱形顶部下方的位置应用virtual继承:

class ICar {
    public:
    virtual void drive() = 0;
};
class IFastCar : virtual public ICar {
    public:
    virtual void driveFast() = 0;
};
class Car : public virtual ICar {
    public:
    void drive() {};
};
class FastCar : public IFastCar, public Car {
    public:
    void driveFast() {};
};
int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    ICar* fc_a = new FastCar;
    fc_a->drive();  // invokes Car::drive() via domination
    return 0;
}

如果你编译&运行上述代码,您将获得所需的行为,但代价是编译器警告。在MSVC10上它是:

1>main.cpp(19): warning C4250: 'FastCar' : inherits 'Car::Car::drive' via dominance
1>          main.cpp(13) : see declaration of 'Car::drive'

这是一个警告,表明您的实现继承体系结构可能搞砸了。事实上,在大多数情况下,它可能是(尽管在这种情况下不是)。这可能很快就会让人感到非常困惑,特别是对于多年后试图弄清楚代码的维护程序员来说。为了消除这种混淆并避免所有编译器警告,我更倾向于(作为规则)将委托给姊妹类而不是实现继承。

class ICar {
    public:
    virtual void drive() = 0;
};
class IFastCar : virtual public ICar {
    public:
    virtual void driveFast() = 0;
};
class ICarImpl 
{
public:
    void drive_impl() {};
};
class IFastCarImpl
{
public :
    void driveFast_impl() {};
};
class Car : public virtual ICar, protected ICarImpl {
    public:
    void drive() { drive_impl(); }
};
class FastCar : public IFastCar, protected ICarImpl, protected IFastCarImpl {
    public:
    void driveFast() { driveFast_impl(); }
    void drive() { drive_impl(); }
};
int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    ICar* fc_a = new FastCar;
    fc_a->drive();  
    return 0;
}

这完成了实现继承的通常目标——只保留一组公共代码,可以跨多个具体类共享,使维护更容易。

因为ICar和IFastCar都是汽车,你可以让IFastCar派生自ICar,然后像你一样实现Car和FastCar。

class ICar {
    public:
    virtual void drive() = 0;
};
class IFastCar : ICar 
{
    public:
    virtual void drive() = 0;
    virtual void driveFast() = 0;
};
class Car : ICar {
    public:
    void drive()
    {
        cout << "driving a normal car" << endl;
    }
};
class FastCar : IFastCar
{
    public:
    void drive()
    {
        cout << "driving a fast car the normal way" << endl;
    }
    void driveFast()
    {
        cout << "driving a fast car at top speed" << endl;
    }
};
int main()
{
    FastCar fc;
    fc.drive();
    fc.driveFast();
    return 0;
}